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.

functions.php 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. <?php
  2. #declare(strict_types=1);
  3. function get_group_info($GroupID, $Return = true, $RevisionID = 0, $PersonalProperties = true, $ApiCall = false)
  4. {
  5. global $Cache, $DB;
  6. if (!$RevisionID) {
  7. $TorrentCache = $Cache->get_value("torrents_details_$GroupID");
  8. }
  9. if ($RevisionID || !is_array($TorrentCache)) {
  10. // Fetch the group details
  11. $SQL = 'SELECT ';
  12. if (!$RevisionID) {
  13. $SQL .= '
  14. g.`description`,
  15. g.`picture`, ';
  16. } else {
  17. $SQL .= '
  18. w.`Body`,
  19. w.`Image`, ';
  20. }
  21. $SQL .= "
  22. g.`id`,
  23. g.`title`,
  24. g.`subject`,
  25. g.`object`,
  26. g.`published`,
  27. g.`workgroup`,
  28. g.`location`,
  29. g.`identifier`,
  30. g.`category_id`,
  31. g.`timestamp`,
  32. GROUP_CONCAT(DISTINCT tags.`Name` SEPARATOR '|'),
  33. GROUP_CONCAT(DISTINCT tags.`ID` SEPARATOR '|'),
  34. GROUP_CONCAT(tt.`UserID` SEPARATOR '|')
  35. FROM `torrents_group` AS g
  36. LEFT JOIN `torrents_tags` AS tt ON tt.`GroupID` = g.`id`
  37. LEFT JOIN `tags` ON tags.`ID` = tt.`TagID`";
  38. if ($RevisionID) {
  39. $SQL .= "
  40. LEFT JOIN `wiki_torrents` AS w ON w.`PageID` = '".db_string($GroupID)."'
  41. AND w.`RevisionID` = '".db_string($RevisionID)."' ";
  42. }
  43. $SQL .= "
  44. WHERE g.`id` = '".db_string($GroupID)."'
  45. GROUP BY NULL";
  46. $DB->query($SQL);
  47. $TorrentDetails = $DB->next_record(MYSQLI_ASSOC);
  48. $TorrentDetails['Screenshots'] = [];
  49. $TorrentDetails['Mirrors'] = [];
  50. # Screenshots (Publications)
  51. $DB->query("
  52. SELECT
  53. `ID`,
  54. `UserID`,
  55. `Time`,
  56. `URI`
  57. FROM
  58. `torrents_doi`
  59. WHERE
  60. `TorrentID` = '$GroupID'
  61. ");
  62. if ($DB->has_results()) {
  63. while ($Screenshot = $DB->next_record(MYSQLI_ASSOC, true)) {
  64. $TorrentDetails['Screenshots'][] = $Screenshot;
  65. }
  66. }
  67. # Mirrors
  68. $DB->query("
  69. SELECT
  70. `ID`,
  71. `UserID`,
  72. `Time`,
  73. `URI`
  74. FROM
  75. `torrents_mirrors`
  76. WHERE
  77. `GroupID` = '$GroupID'
  78. ");
  79. if ($DB->has_results()) {
  80. while ($Mirror = $DB->next_record(MYSQLI_ASSOC, true)) {
  81. $TorrentDetails['Mirrors'][] = $Mirror;
  82. }
  83. }
  84. // Fetch the individual torrents
  85. $DB->query("
  86. SELECT
  87. t.ID,
  88. t.Media,
  89. t.Container,
  90. t.Codec,
  91. t.Resolution,
  92. t.Version,
  93. t.Censored,
  94. t.Anonymous,
  95. t.Archive,
  96. t.FileCount,
  97. t.Size,
  98. t.Seeders,
  99. t.Leechers,
  100. t.Snatched,
  101. t.FreeTorrent,
  102. t.FreeLeechType,
  103. t.Time,
  104. t.Description,
  105. t.FileList,
  106. t.FilePath,
  107. t.UserID,
  108. t.last_action,
  109. HEX(t.info_hash) AS InfoHash,
  110. tbt.TorrentID AS BadTags,
  111. tbf.TorrentID AS BadFolders,
  112. tfi.TorrentID AS BadFiles,
  113. t.LastReseedRequest,
  114. tln.TorrentID AS LogInDB,
  115. t.ID AS HasFile
  116. FROM torrents AS t
  117. LEFT JOIN torrents_bad_tags AS tbt ON tbt.TorrentID = t.ID
  118. LEFT JOIN torrents_bad_folders AS tbf ON tbf.TorrentID = t.ID
  119. LEFT JOIN torrents_bad_files AS tfi ON tfi.TorrentID = t.ID
  120. LEFT JOIN torrents_logs_new AS tln ON tln.TorrentID = t.ID
  121. WHERE t.GroupID = '".db_string($GroupID)."'
  122. GROUP BY t.ID
  123. ORDER BY
  124. t.Media ASC,
  125. t.ID");
  126. $TorrentList = $DB->to_array('ID', MYSQLI_ASSOC);
  127. if (count($TorrentList) === 0 && $ApiCall == false) {
  128. header('Location: log.php?search='.(empty($_GET['torrentid']) ? "Group+$GroupID" : "Torrent+$_GET[torrentid]"));
  129. error();
  130. } elseif (count($TorrentList) === 0 && $ApiCall == true) {
  131. return;
  132. }
  133. if (in_array(0, $DB->collect('Seeders'))) {
  134. $CacheTime = 600;
  135. } else {
  136. $CacheTime = 3600;
  137. }
  138. // Store it all in cache
  139. if (!$RevisionID) {
  140. $Cache->cache_value("torrents_details_$GroupID", array($TorrentDetails, $TorrentList), $CacheTime);
  141. }
  142. } else { // If we're reading from cache
  143. $TorrentDetails = $TorrentCache[0];
  144. $TorrentList = $TorrentCache[1];
  145. }
  146. if ($PersonalProperties) {
  147. // Fetch all user specific torrent and group properties
  148. $TorrentDetails['Flags'] = array('IsSnatched' => false, 'IsLeeching' => false, 'IsSeeding' => false);
  149. foreach ($TorrentList as &$Torrent) {
  150. Torrents::torrent_properties($Torrent, $TorrentDetails['Flags']);
  151. }
  152. }
  153. if ($Return) {
  154. return array($TorrentDetails, $TorrentList);
  155. }
  156. }
  157. function get_torrent_info($TorrentID, $Return = true, $RevisionID = 0, $PersonalProperties = true, $ApiCall = false)
  158. {
  159. global $Cache, $DB;
  160. $GroupID = (int)torrentid_to_groupid($TorrentID);
  161. $GroupInfo = get_group_info($GroupID, $Return, $RevisionID, $PersonalProperties, $ApiCall);
  162. if ($GroupInfo) {
  163. foreach ($GroupInfo[1] as &$Torrent) {
  164. // Remove unneeded entries
  165. if ($Torrent['ID'] !== $TorrentID) {
  166. unset($GroupInfo[1][$Torrent['ID']]);
  167. }
  168. if ($Return) {
  169. return $GroupInfo;
  170. }
  171. }
  172. } else {
  173. if ($Return) {
  174. return;
  175. }
  176. }
  177. }
  178. // Check if a givin string can be validated as a torrenthash
  179. function is_valid_torrenthash($Str)
  180. {
  181. // 6C19FF4C 6C1DD265 3B25832C 0F6228B2 52D743D5
  182. $Str = str_replace(' ', '', $Str);
  183. if (preg_match('/^[0-9a-fA-F]{40}$/', $Str)) {
  184. return $Str;
  185. }
  186. return false;
  187. }
  188. // Functionality for the API to resolve input into other data
  189. function torrenthash_to_torrentid($Str)
  190. {
  191. global $Cache, $DB;
  192. $DB->query("
  193. SELECT ID
  194. FROM torrents
  195. WHERE HEX(info_hash) = '".db_string($Str)."'");
  196. $TorrentID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
  197. if ($TorrentID) {
  198. return $TorrentID;
  199. }
  200. return;
  201. }
  202. function torrenthash_to_groupid($Str)
  203. {
  204. global $Cache, $DB;
  205. $DB->query("
  206. SELECT GroupID
  207. FROM torrents
  208. WHERE HEX(info_hash) = '".db_string($Str)."'");
  209. $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
  210. if ($GroupID) {
  211. return $GroupID;
  212. }
  213. return;
  214. }
  215. function torrentid_to_groupid($TorrentID)
  216. {
  217. global $Cache, $DB;
  218. $DB->query("
  219. SELECT GroupID
  220. FROM torrents
  221. WHERE ID = '".db_string($TorrentID)."'");
  222. $GroupID = (int)array_pop($DB->next_record(MYSQLI_ASSOC));
  223. if ($GroupID) {
  224. return $GroupID;
  225. }
  226. return;
  227. }
  228. // After adjusting / deleting logs, recalculate the score for the torrent
  229. function set_torrent_logscore($TorrentID)
  230. {
  231. global $DB;
  232. $DB->query("
  233. UPDATE torrents
  234. SET LogScore = (
  235. SELECT FLOOR(AVG(Score))
  236. FROM torrents_logs_new
  237. WHERE TorrentID = $TorrentID
  238. )
  239. WHERE ID = $TorrentID");
  240. }
  241. function get_group_requests($GroupID)
  242. {
  243. if (empty($GroupID) || !is_number($GroupID)) {
  244. return [];
  245. }
  246. global $DB, $Cache;
  247. $Requests = $Cache->get_value("requests_group_$GroupID");
  248. if ($Requests === false) {
  249. $DB->query("
  250. SELECT ID
  251. FROM requests
  252. WHERE GroupID = $GroupID
  253. AND TimeFilled IS NULL");
  254. $Requests = $DB->collect('ID');
  255. $Cache->cache_value("requests_group_$GroupID", $Requests, 0);
  256. }
  257. return Requests::get_requests($Requests);
  258. }
  259. // Used by both sections/torrents/details.php and sections/reportsv2/report.php
  260. function build_torrents_table($Cache, $DB, $LoggedUser, $GroupID, $GroupName, $GroupCategoryID, $TorrentList, $Types, $Username)
  261. {
  262. function filelist($Str)
  263. {
  264. return "</td>\n<td>" . Format::get_size($Str[1]) . "</td>\n</tr>";
  265. }
  266. $EditionID = 0;
  267. foreach ($TorrentList as $Torrent) {
  268. list($TorrentID, $Media, $Container, $Codec, $Resolution, $Version,
  269. $Censored, $Anonymous, $Archive, $FileCount, $Size, $Seeders, $Leechers, $Snatched,
  270. $FreeTorrent, $FreeLeechType, $TorrentTime, $Description, $FileList, $FilePath, $UserID,
  271. $LastActive, $InfoHash, $BadTags, $BadFolders, $BadFiles, $LastReseedRequest,
  272. $LogInDB, $HasFile, $PersonalFL, $IsSnatched, $IsSeeding, $IsLeeching) = array_values($Torrent);
  273. $Reported = false;
  274. $Reports = Torrents::get_reports($TorrentID);
  275. $NumReports = count($Reports);
  276. if ($NumReports > 0) {
  277. $Reported = true;
  278. include(SERVER_ROOT.'/sections/reportsv2/array.php');
  279. $ReportInfo = '
  280. <table class="reportinfo_table">
  281. <tr class="colhead_dark" style="font-weight: bold;">
  282. <td>This torrent has '.$NumReports.' active '.($NumReports === 1 ? 'report' : 'reports').":</td>
  283. </tr>";
  284. foreach ($Reports as $Report) {
  285. if (check_perms('admin_reports')) {
  286. $ReporterID = $Report['ReporterID'];
  287. $Reporter = Users::user_info($ReporterID);
  288. $ReporterName = $Reporter['Username'];
  289. $ReportLinks = "<a href=\"user.php?id=$ReporterID\">$ReporterName</a> <a href=\"reportsv2.php?view=report&amp;id=$Report[ID]\">reported it</a>";
  290. } else {
  291. $ReportLinks = 'Someone reported it';
  292. }
  293. if (isset($Types[$GroupCategoryID][$Report['Type']])) {
  294. $ReportType = $Types[$GroupCategoryID][$Report['Type']];
  295. } elseif (isset($Types['master'][$Report['Type']])) {
  296. $ReportType = $Types['master'][$Report['Type']];
  297. } else {
  298. // There was a type but it wasn't an option!
  299. $ReportType = $Types['master']['other'];
  300. }
  301. $ReportInfo .= "
  302. <tr>
  303. <td>$ReportLinks ".time_diff($Report['ReportedTime'], 2, true, true).' for the reason "'.$ReportType['title'].'":
  304. <blockquote>'.Text::full_format($Report['UserComment']).'</blockquote>
  305. </td>
  306. </tr>';
  307. }
  308. $ReportInfo .= "</table>";
  309. }
  310. $CanEdit = (check_perms('torrents_edit') || (($UserID == $LoggedUser['ID'] && !$LoggedUser['DisableWiki'])));
  311. $RegenLink = check_perms('users_mod') ? ' <a href="torrents.php?action=regen_filelist&amp;torrentid=' . $TorrentID . '" class="brackets">Regenerate</a>' : '';
  312. $FileTable = '
  313. <table class="filelist_table">
  314. <tr class="colhead_dark">
  315. <td>
  316. <div class="filelist_title float_left">File Names' . $RegenLink . '</div>
  317. <div class="filelist_path float_right">' . ($FilePath ? "/$FilePath/" : '') . '</div>
  318. </td>
  319. <td>
  320. <strong>Size</strong>
  321. </td>
  322. </tr>';
  323. if (substr($FileList, -3) == '}}}') { // Old style
  324. $FileListSplit = explode('|||', $FileList);
  325. foreach ($FileListSplit as $File) {
  326. $NameEnd = strrpos($File, '{{{');
  327. $Name = substr($File, 0, $NameEnd);
  328. if ($Spaces = strspn($Name, ' ')) {
  329. $Name = str_replace(' ', '&nbsp;', substr($Name, 0, $Spaces)) . substr($Name, $Spaces);
  330. }
  331. $FileSize = substr($File, $NameEnd + 3, -3);
  332. $FileTable .= sprintf("\n<tr class=\"row\"><td>%s</td><td class=\"number_column\">%s</td></tr>", $Name, Format::get_size($FileSize));
  333. }
  334. } else {
  335. $FileListSplit = explode("\n", $FileList);
  336. foreach ($FileListSplit as $File) {
  337. $FileInfo = Torrents::filelist_get_file($File);
  338. $FileTable .= sprintf("\n<tr class=\"row\"><td>%s</td><td class=\"number_column\">%s</td></tr>", $FileInfo['name'], Format::get_size($FileInfo['size']));
  339. }
  340. }
  341. $FileTable .= '</table>';
  342. $ExtraInfo = ''; // String that contains information on the torrent (e.g. format and encoding)
  343. $AddExtra = '&thinsp;|&thinsp;'; // Separator between torrent properties
  344. $TorrentUploader = $Username; // Save this for "Uploaded by:" below
  345. // Similar to Torrents::torrent_info()
  346. if (!$ExtraInfo) {
  347. $ExtraInfo = $GroupName;
  348. }
  349. if ($IsLeeching) {
  350. $ExtraInfo .= $AddExtra.Format::torrent_label('Leeching', 'important_text_semi');
  351. } elseif ($IsSeeding) {
  352. $ExtraInfo .= $AddExtra.Format::torrent_label('Seeding', 'important_text_alt');
  353. } elseif ($IsSnatched) {
  354. $ExtraInfo .= $AddExtra.Format::torrent_label('Snatched', 'bold');
  355. }
  356. if ($FreeTorrent === 1) {
  357. $ExtraInfo .= $AddExtra.Format::torrent_label('Freeleech', 'important_text_alt');
  358. }
  359. if ($FreeTorrent === 2) {
  360. $ExtraInfo .= $AddExtra.Format::torrent_label('Neutral Leech', 'bold');
  361. }
  362. if ($PersonalFL) {
  363. $ExtraInfo .= $AddExtra.Format::torrent_label('Personal Freeleech', 'important_text_alt');
  364. }
  365. if ($Reported) {
  366. $ExtraInfo .= $AddExtra.Format::torrent_label('Reported', 'tl_reported');
  367. }
  368. if (!empty($BadTags)) {
  369. $ExtraInfo .= $AddExtra.Format::torrent_label('Bad Tags', 'tl_reported');
  370. }
  371. if (!empty($BadFolders)) {
  372. $ExtraInfo .= $AddExtra.Format::torrent_label('Bad Folders', 'tl_reported');
  373. }
  374. if (!empty($BadFiles)) {
  375. $ExtraInfo .= $AddExtra.Format::torrent_label('Bad File Names', 'tl_reported');
  376. } ?>
  377. <tr class="torrent_row<?=(isset($ReleaseType)?' releases_'.$ReleaseType:'')?> groupid_<?=($GroupID)?> edition_<?=($EditionID)?> group_torrent<?=($IsSnatched ? ' snatched_torrent' : '')?>"
  378. style="font-weight: normal;" id="torrent<?=($TorrentID)?>">
  379. <td>
  380. <span>[ <a
  381. href="torrents.php?action=download&amp;id=<?=($TorrentID)?>&amp;authkey=<?=($LoggedUser['AuthKey'])?>&amp;torrent_pass=<?=($LoggedUser['torrent_pass'])?>"
  382. class="tooltip" title="Download"><?=($HasFile ? 'DL' : 'Missing')?></a>
  383. <?php if (Torrents::can_use_token($Torrent)) { ?>
  384. | <a href="torrents.php?action=download&amp;id=<?=($TorrentID)?>&amp;authkey=<?=($LoggedUser['AuthKey'])?>&amp;torrent_pass=<?=($LoggedUser['torrent_pass'])?>&amp;usetoken=1"
  385. class="tooltip" title="Use a FL Token"
  386. onclick="return confirm('Are you sure you want to use a freeleech token here?');">FL</a>
  387. <?php } ?>
  388. | <a href="reportsv2.php?action=report&amp;id=<?=($TorrentID)?>"
  389. class="tooltip" title="Report">RP</a>
  390. <?php if ($CanEdit) { ?>
  391. | <a href="torrents.php?action=edit&amp;id=<?=($TorrentID)?>"
  392. class="tooltip" title="Edit">ED</a>
  393. <?php }
  394. if (check_perms('torrents_delete') || $UserID == $LoggedUser['ID']) { ?>
  395. | <a href="torrents.php?action=delete&amp;torrentid=<?=($TorrentID)?>"
  396. class="tooltip" title="Remove">RM</a>
  397. <?php } ?>
  398. | <a href="torrents.php?torrentid=<?=($TorrentID)?>"
  399. class="tooltip" title="Permalink">PL</a>
  400. ]
  401. </span>
  402. <a data-toggle-target="#torrent_<?=($TorrentID)?>"><?=($ExtraInfo)?></a>
  403. </td>
  404. <td class="number_column nobr"><?=(Format::get_size($Size))?>
  405. </td>
  406. <td class="number_column"><?=(number_format($Snatched))?>
  407. </td>
  408. <td class="number_column"><?=(number_format($Seeders))?>
  409. </td>
  410. <td class="number_column"><?=(number_format($Leechers))?>
  411. </td>
  412. </tr>
  413. <tr class="<?=(isset($ReleaseType)?'releases_'.$ReleaseType:'')?> groupid_<?=($GroupID)?> edition_<?=($EditionID)?> torrentdetails pad<?php if (!isset($_GET['torrentid']) || $_GET['torrentid'] != $TorrentID) { ?> hidden<?php } ?>"
  414. id="torrent_<?=($TorrentID)?>">
  415. <td colspan="5">
  416. <blockquote>
  417. Uploaded by <?php
  418. if ($Anonymous) {
  419. if (check_perms('users_mod')) { ?>
  420. <em class="tooltip"
  421. title="<?=Users::user_info($UserID)['Username']?>">Anonymous</em>
  422. <?php } else {
  423. ?><em>Anonymous</em><?php
  424. }
  425. } else {
  426. print(Users::format_username($UserID, false, false, false));
  427. } ?> <?=time_diff($TorrentTime); ?>
  428. <?php if ($Seeders === 0) {
  429. if ($LastActive && time() - strtotime($LastActive) >= 1209600) { ?>
  430. <br /><strong>Last active: <?=time_diff($LastActive);?></strong>
  431. <?php } else { ?>
  432. <br />Last active: <?=time_diff($LastActive);?>
  433. <?php }
  434. if ($LastActive && time() - strtotime($LastActive) >= 345678 && time() - strtotime($LastReseedRequest) >= 864000) { ?>
  435. <br /><a
  436. href="torrents.php?action=reseed&amp;torrentid=<?=($TorrentID)?>&amp;groupid=<?=($GroupID)?>"
  437. class="brackets">Request re-seed</a>
  438. <?php }
  439. } ?>
  440. </blockquote>
  441. <?php if (check_perms('site_moderate_requests')) { ?>
  442. <div class="linkbox">
  443. <a href="torrents.php?action=masspm&amp;id=<?=($GroupID)?>&amp;torrentid=<?=($TorrentID)?>"
  444. class="brackets">Mass PM snatchers</a>
  445. </div>
  446. <?php } ?>
  447. <div class="linkbox">
  448. <a href="#" class="brackets"
  449. onclick="show_peers('<?=($TorrentID)?>', 0); return false;">View
  450. peer list</a>
  451. <?php if (check_perms('site_view_torrent_snatchlist')) { ?>
  452. <a href="#" class="brackets tooltip"
  453. onclick="show_downloads('<?=($TorrentID)?>', 0); return false;"
  454. title="View the list of users that have clicked the &quot;DL&quot; button.">View download list</a>
  455. <a href="#" class="brackets tooltip"
  456. onclick="show_snatches('<?=($TorrentID)?>', 0); return false;"
  457. title="View the list of users that have reported a snatch to the tracker.">View snatch list</a>
  458. <?php } ?>
  459. <a href="#" class="brackets"
  460. onclick="show_files('<?=($TorrentID)?>'); return false;">View
  461. file list</a>
  462. <?php if ($Reported) { ?>
  463. <a href="#" class="brackets"
  464. onclick="show_reported('<?=($TorrentID)?>'); return false;">View
  465. report information</a>
  466. <?php } ?>
  467. </div>
  468. <div id="peers_<?=($TorrentID)?>" class="hidden"></div>
  469. <div id="downloads_<?=($TorrentID)?>" class="hidden"></div>
  470. <div id="snatches_<?=($TorrentID)?>" class="hidden"></div>
  471. <div id="files_<?=($TorrentID)?>" class="hidden"><?=($FileTable)?>
  472. </div>
  473. <?php if ($Reported) { ?>
  474. <div id="reported_<?=($TorrentID)?>" class="hidden"><?=($ReportInfo)?>
  475. </div>
  476. <?php }
  477. if (!empty($Description)) {
  478. echo "<blockquote>" . Text::full_format($Description) . '</blockquote>';
  479. } ?>
  480. </td>
  481. </tr>
  482. <?php
  483. }
  484. }