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.

upload_handle.php 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. <?php
  2. //****************************************************************************//
  3. //--------------- Take upload ------------------------------------------------//
  4. // This pages handles the backend of the torrent upload function. It checks //
  5. // the data, and if it all validates, it builds the torrent file, then writes //
  6. // the data to the database and the torrent to the disk. //
  7. //****************************************************************************//
  8. // Maximum allowed size for uploaded files
  9. // https://php.net/upload-max-filesize
  10. ini_set('upload_max_filesize', 2097152); // 2 MiB
  11. ini_set('max_file_uploads', 100);
  12. define('MAX_FILENAME_LENGTH', 180);
  13. include(SERVER_ROOT.'/classes/validate.class.php');
  14. include(SERVER_ROOT.'/classes/feed.class.php');
  15. include(SERVER_ROOT.'/sections/torrents/functions.php');
  16. include(SERVER_ROOT.'/classes/file_checker.class.php');
  17. enforce_login();
  18. authorize();
  19. $Validate = new VALIDATE;
  20. $Feed = new FEED;
  21. //*****************************************************************************//
  22. //--------------- Set $Properties array ---------------------------------------//
  23. // This is used if the form doesn't validate, and when the time comes to enter //
  24. // it into the database. //
  25. // Haha wow god i'm trying to restrict the database to only have fields for //
  26. // movies and not add anything for other categories but this is fucking dumb //
  27. $Properties = [];
  28. $Type = $Categories[(int)$_POST['type']];
  29. $TypeID = $_POST['type'] + 1;
  30. $Properties['CategoryID'] = $TypeID;
  31. $Properties['CategoryName'] = $Type;
  32. $Properties['Title'] = $_POST['title'];
  33. $Properties['TitleRJ'] = $_POST['title_rj'];
  34. $Properties['TitleJP'] = $_POST['title_jp'];
  35. $Properties['Year'] = $_POST['year'];
  36. $Properties['Studio'] = isset($_POST['studio']) ? $_POST['studio'] : '';
  37. $Properties['Series'] = isset($_POST['series']) ? $_POST['series'] : '';
  38. $Properties['CatalogueNumber'] = isset($_POST['catalogue']) ? $_POST['catalogue'] : '';
  39. $Properties['Pages'] = isset($_POST['pages']) ? $_POST['pages'] : 0;
  40. $Properties['Container'] = isset($_POST['container']) ? $_POST['container'] : '';
  41. $Properties['Media'] = $_POST['media'];
  42. $Properties['Codec'] = isset($_POST['codec']) ? $_POST['codec'] : '';
  43. if (!($_POST['resolution'] ?? false)) {
  44. $_POST['resolution'] = $_POST['ressel'] ?? '';
  45. }
  46. $Properties['Resolution'] = $_POST['resolution'] ?? '';
  47. $Properties['AudioFormat'] = 'nil';
  48. $Properties['Subbing'] = 'nil';
  49. $Properties['Language'] = 'nil';
  50. $Properties['Subber'] = isset($_POST['subber']) ? $_POST['subber'] : '';
  51. $Properties['DLsiteID'] = (isset($_POST['dlsiteid'])) ? $_POST['dlsiteid'] : '';
  52. $Properties['Censored'] = (isset($_POST['censored'])) ? '1' : '0';
  53. $Properties['Anonymous'] = (isset($_POST['anonymous'])) ? '1' : '0';
  54. $Properties['Archive'] = (isset($_POST['archive']) && $_POST['archive'] !== '---') ? $_POST['archive'] : '';
  55. if (isset($_POST['library_image'])) {
  56. $Properties['LibraryImage'] = $_POST['library_image'];
  57. }
  58. if (isset($_POST['tags'])) {
  59. $Properties['TagList'] = implode(',', array_unique(explode(',', str_replace(' ', '', $_POST['tags']))));
  60. }
  61. if (isset($_POST['image'])) {
  62. $Properties['Image'] = $_POST['image'];
  63. }
  64. if (isset($_POST['release'])) {
  65. $Properties['ReleaseGroup'] = $_POST['release'];
  66. }
  67. $Properties['GroupDescription'] = trim($_POST['album_desc']);
  68. $Properties['TorrentDescription'] = $_POST['release_desc'];
  69. $Properties['MediaInfo'] = 'nil';
  70. $Properties['Screenshots'] = isset($_POST['screenshots']) ? $_POST['screenshots'] : "";
  71. if ($_POST['album_desc']) {
  72. $Properties['GroupDescription'] = trim($_POST['album_desc']);
  73. } elseif ($_POST['desc']) {
  74. $Properties['GroupDescription'] = trim($_POST['desc']);
  75. $Properties['MediaInfo'] = 'nil';
  76. }
  77. if (isset($_POST['groupid'])) {
  78. $Properties['GroupID'] = $_POST['groupid'];
  79. }
  80. if (isset($Properties['GroupID'])) {
  81. $Properties['Artists'] = Artists::get_artist($Properties['GroupID']);
  82. }
  83. if ($Type === 'Movies' || $Type === 'Manga' || $Type === 'Anime' || $Type === 'Games') {
  84. if (empty($_POST['idols'])) {
  85. $Err = "You didn't enter any artists/idols";
  86. } else {
  87. $Artists = $_POST['idols'];
  88. }
  89. } else {
  90. if (!empty($_POST['idols'])) {
  91. $Artists = $_POST['idols'];
  92. }
  93. }
  94. if (!empty($_POST['requestid'])) {
  95. $RequestID = $_POST['requestid'];
  96. $Properties['RequestID'] = $RequestID;
  97. }
  98. //******************************************************************************//
  99. //--------------- Validate data in upload form ---------------------------------//
  100. $Validate->SetFields('type', '1', 'inarray', 'Please select a valid type.', array('inarray' => array_keys($Categories)));
  101. switch ($Type) {
  102. /*
  103. case 'Movies':
  104. case 'Anime':
  105. $Validate->SetFields('codec',
  106. '1','inarray','Please select a valid codec.', array('inarray'=>$Codecs));
  107. $Validate->SetFields('resolution',
  108. '1','regex','Please set a valid resolution.', array('regex'=>'/^(SD)|([0-9]+(p|i))|([0-9]K)|([0-9]+x[0-9]+)$/'));
  109. $Validate->SetFields('audioformat',
  110. '1','inarray','Please select a valid audio format.', array('inarray'=>$AudioFormats));
  111. $Validate->SetFields('sub',
  112. '1','inarray','Please select a valid sub format.', array('inarray'=>$Subbing));
  113. $Validate->SetFields('censored', '1', 'inarray', 'Set valid censoring', array('inarray'=>array(0, 1)));
  114. case 'Games':
  115. $Validate->SetFields('container',
  116. '1','inarray','Please select a valid container.', array('inarray'=>array_merge($Containers, $ContainersGames)));
  117. case 'Manga':
  118. if (!isset($_POST['groupid']) || !$_POST['groupid']) {
  119. $Validate->SetFields('year',
  120. '1','number','The year of the original release must be entered.', array('maxlength'=>3000, 'minlength'=>1800));
  121. if ($Type === 'Manga') {
  122. $Validate->SetFields('pages',
  123. '1', 'number', 'That is not a valid page count', array('minlength'=>1));
  124. }
  125. }
  126. $Validate->SetFields('media',
  127. '1','inarray','Please select a valid media/platform.', array('inarray'=>array_merge($Media, $MediaManga, $Platform)));
  128. $Validate->SetFields('lang',
  129. '1','inarray','Please select a valid language.', array('inarray'=>$Languages));
  130. $Validate->SetFields('release_desc',
  131. '0','string','The release description has a minimum length of 10 characters.', array('maxlength'=>1000000, 'minlength'=>10));
  132. */
  133. default:
  134. if (!isset($_POST['groupid']) || !$_POST['groupid']) {
  135. $Validate->SetFields(
  136. 'title',
  137. '0',
  138. 'string',
  139. 'Sequence Name must be between 1 and 512 characters.',
  140. array('maxlength'=>512, 'minlength'=>1)
  141. );
  142. $Validate->SetFields(
  143. 'title_rj',
  144. '0',
  145. 'string',
  146. 'Organism must be between 1 and 512 characters.',
  147. array('maxlength'=>512, 'minlength'=>1)
  148. );
  149. $Validate->SetFields(
  150. 'title_jp',
  151. '0',
  152. 'string',
  153. 'Strain/Variety must be between 1 and 512 characters.',
  154. array('maxlength'=>512, 'minlength'=>1)
  155. );
  156. $Validate->SetFields(
  157. 'tags',
  158. '1',
  159. 'string',
  160. 'You must enter at least five tags. Maximum length is 1500 characters.',
  161. array('maxlength'=>1500, 'minlength'=>2)
  162. );
  163. $Validate->SetFields(
  164. 'image',
  165. '0',
  166. 'link',
  167. 'The image URL you entered was invalid.',
  168. array('maxlength'=>255, 'minlength'=>12)
  169. );
  170. }
  171. $Validate->SetFields(
  172. 'album_desc',
  173. '1',
  174. 'string',
  175. 'The description has a minimum length of 10 characters.',
  176. array('maxlength'=>1000000, 'minlength'=>10)
  177. );
  178. #$Validate->SetFields('groupid', '0', 'number', 'Group ID was not numeric.');
  179. }
  180. $Err = $Validate->ValidateForm($_POST); // Validate the form
  181. if (count(explode(',', $Properties['TagList'])) < 5) {
  182. $Err = 'You must enter at least 5 tags.';
  183. }
  184. if (!(isset($_POST['title']) || isset($_POST['title_rj']) || isset($_POST['title_jp']))) {
  185. $Err = 'You must enter at least one title.';
  186. }
  187. $File = $_FILES['file_input']; // This is our torrent file
  188. $TorrentName = $File['tmp_name'];
  189. if (!is_uploaded_file($TorrentName) || !filesize($TorrentName)) {
  190. $Err = 'No torrent file uploaded, or file is empty.';
  191. } elseif (substr(strtolower($File['name']), strlen($File['name']) - strlen('.torrent')) !== '.torrent') {
  192. $Err = "You seem to have put something other than a torrent file into the upload field. (".$File['name'].").";
  193. }
  194. // Multiple artists!
  195. $LogName = '';
  196. if (empty($Properties['GroupID']) && empty($ArtistForm)) {
  197. $ArtistNames = [];
  198. $ArtistForm = [];
  199. for ($i = 0; $i < count($Artists); $i++) {
  200. if (trim($Artists[$i]) !== '') {
  201. if (!in_array($Artists[$i], $ArtistNames)) {
  202. $ArtistForm[$i] = array('name' => Artists::normalise_artist_name($Artists[$i]));
  203. array_push($ArtistNames, $ArtistForm[$i]['name']);
  204. }
  205. }
  206. }
  207. $LogName .= Artists::display_artists($ArtistForm, false, true, false);
  208. } elseif (empty($ArtistForm)) {
  209. $DB->query("
  210. SELECT ta.ArtistID, ag.Name
  211. FROM torrents_artists AS ta
  212. JOIN artists_group AS ag ON ta.ArtistID = ag.ArtistID
  213. WHERE ta.GroupID = ?
  214. ORDER BY ag.Name ASC", $Properties['GroupID']);
  215. $ArtistForm = [];
  216. while (list($ArtistID, $ArtistName) = $DB->next_record(MYSQLI_BOTH, false)) {
  217. array_push($ArtistForm, array('id' => $ArtistID, 'name' => display_str($ArtistName)));
  218. array_push($ArtistsUnescaped, array('name' => $ArtistName));
  219. }
  220. $LogName .= Artists::display_artists($ArtistsUnescaped, false, true, false);
  221. }
  222. if ($Err) { // Show the upload form, with the data the user entered
  223. $UploadForm = $Type;
  224. include(SERVER_ROOT.'/sections/upload/upload.php');
  225. die();
  226. }
  227. ImageTools::blacklisted($Properties['Image']);
  228. //******************************************************************************//
  229. //--------------- Make variables ready for database input ----------------------//
  230. // Prepared SQL statements do this for us, so there is nothing to do here anymore
  231. $T = $Properties;
  232. //******************************************************************************//
  233. //--------------- Generate torrent file ----------------------------------------//
  234. $Tor = new BencodeTorrent($TorrentName, true);
  235. $PublicTorrent = $Tor->make_private(); // The torrent is now private
  236. $UnsourcedTorrent = $Tor->make_sourced(); // The torrent now has the source field set
  237. $InfoHash = pack('H*', $Tor->info_hash());
  238. if (isset($Tor->Dec['encrypted_files'])) {
  239. $Err = 'This torrent contains an encrypted file list which is not supported here.';
  240. }
  241. // File list and size
  242. list($TotalSize, $FileList) = $Tor->file_list();
  243. $NumFiles = count($FileList);
  244. $TmpFileList = [];
  245. $TooLongPaths = [];
  246. $DirName = (isset($Tor->Dec['info']['files']) ? Format::make_utf8($Tor->get_name()) : '');
  247. check_name($DirName); // Check the folder name against the blacklist
  248. foreach ($FileList as $File) {
  249. list($Size, $Name) = $File;
  250. // Check file name and extension against blacklist/whitelist
  251. check_file($Type, $Name);
  252. // Make sure the filename is not too long
  253. if (mb_strlen($Name, 'UTF-8') + mb_strlen($DirName, 'UTF-8') + 1 > MAX_FILENAME_LENGTH) {
  254. $TooLongPaths[] = "$DirName/$Name";
  255. }
  256. // Add file info to array
  257. $TmpFileList[] = Torrents::filelist_format_file($File);
  258. }
  259. if (count($TooLongPaths) > 0) {
  260. $Names = implode(' <br />', $TooLongPaths);
  261. $Err = "The torrent contained one or more files with too long a name:<br /> $Names";
  262. }
  263. $FilePath = $DirName;
  264. $FileString = implode("\n", $TmpFileList);
  265. $Debug->set_flag('upload: torrent decoded');
  266. if (!empty($Err)) { // Show the upload form, with the data the user entered
  267. $UploadForm = $Type;
  268. include(SERVER_ROOT.'/sections/upload/upload.php');
  269. die();
  270. }
  271. //******************************************************************************//
  272. //--------------- Start database stuff -----------------------------------------//
  273. $Body = $T['GroupDescription'];
  274. // Trickery
  275. if (!preg_match('/^'.IMAGE_REGEX.'$/i', $T['Image'])) {
  276. $T['Image'] = '';
  277. }
  278. // Does it belong in a group?
  279. if ($T['GroupID']) {
  280. $DB->query("
  281. SELECT
  282. ID,
  283. WikiImage,
  284. WikiBody,
  285. RevisionID,
  286. Name,
  287. Year,
  288. TagList
  289. FROM torrents_group
  290. WHERE id = ?", $T['GroupID']);
  291. if ($DB->has_results()) {
  292. // Don't escape tg.Name. It's written directly to the log table
  293. list($GroupID, $WikiImage, $WikiBody, $RevisionID, $T['Title'], $T['Year'], $T['TagList']) = $DB->next_record(MYSQLI_NUM, array(4));
  294. $T['TagList'] = str_replace(array(' ', '.', '_'), array(', ', '.', '.'), $T['TagList']);
  295. if (!$T['Image'] && $WikiImage) {
  296. $T['Image'] = $WikiImage;
  297. }
  298. if (strlen($WikiBody) > strlen($Body)) {
  299. $Body = $WikiBody;
  300. if (!$T['Image'] || $T['Image'] === $WikiImage) {
  301. $NoRevision = true;
  302. }
  303. }
  304. $T['Artist'] = Artists::display_artists(Artists::get_artist($GroupID), false, false);
  305. }
  306. }
  307. if (!isset($GroupID) || !$GroupID) {
  308. foreach ($ArtistForm as $Num => $Artist) {
  309. // The album hasn't been uploaded. Try to get the artist IDs
  310. $DB->query("
  311. SELECT
  312. ArtistID,
  313. Name
  314. FROM artists_group
  315. WHERE Name = ?", $Artist['name']);
  316. if ($DB->has_results()) {
  317. while (list($ArtistID, $Name) = $DB->next_record(MYSQLI_NUM, false)) {
  318. if (!strcasecmp($Artist['name'], $Name)) {
  319. $ArtistForm[$Num] = ['id' => $ArtistID, 'name' => $Name];
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. // Needs to be here as it isn't set for add format until now
  327. $LogName .= $T['Title'];
  328. // For notifications---take note now whether it's a new group
  329. $IsNewGroup = !isset($GroupID) || !$GroupID;
  330. //----- Start inserts
  331. if ((!isset($GroupID) || !$GroupID)) {
  332. // Array to store which artists we have added already, to prevent adding an artist twice
  333. $ArtistsAdded = [];
  334. foreach ($ArtistForm as $Num => $Artist) {
  335. if (!isset($Artist['id']) || !$Artist['id']) {
  336. if (isset($ArtistsAdded[strtolower($Artist['name'])])) {
  337. $ArtistForm[$Num] = $ArtistsAdded[strtolower($Artist['name'])];
  338. } else {
  339. // Create artist
  340. $DB->query("
  341. INSERT INTO artists_group (Name)
  342. VALUES ( ? )", $Artist['name']);
  343. $ArtistID = $DB->inserted_id();
  344. $Cache->increment('stats_artist_count');
  345. $ArtistForm[$Num] = array('id' => $ArtistID, 'name' => $Artist['name']);
  346. $ArtistsAdded[strtolower($Artist['name'])] = $ArtistForm[$Num];
  347. }
  348. }
  349. }
  350. unset($ArtistsAdded);
  351. }
  352. if (!isset($GroupID) || !$GroupID) {
  353. // Create torrent group
  354. $DB->query(
  355. "
  356. INSERT INTO torrents_group
  357. (CategoryID, Name, NameRJ, NameJP, Year,
  358. Series, Studio, CatalogueNumber, Pages, Time,
  359. WikiBody, WikiImage, DLsiteID)
  360. VALUES
  361. ( ?, ?, ?, ?, ?,
  362. ?, ?, ?, ?, NOW(),
  363. ?, ?, ? )",
  364. $TypeID,
  365. $T['Title'],
  366. $T['TitleRJ'],
  367. $T['TitleJP'],
  368. $T['Year'],
  369. $T['Series'],
  370. $T['Studio'],
  371. $T['CatalogueNumber'],
  372. $T['Pages'],
  373. $Body,
  374. $T['Image'],
  375. $T['DLsiteID']
  376. );
  377. $GroupID = $DB->inserted_id();
  378. foreach ($ArtistForm as $Num => $Artist) {
  379. $DB->query("
  380. INSERT IGNORE INTO torrents_artists (GroupID, ArtistID, UserID)
  381. VALUES ( ?, ?, ? )", $GroupID, $Artist['id'], $LoggedUser['ID']);
  382. $Cache->increment('stats_album_count');
  383. $Cache->delete_value('artist_groups_'.$Artist['id']);
  384. }
  385. $Cache->increment('stats_group_count');
  386. // Add screenshots
  387. $Screenshots = explode("\n", $T['Screenshots']);
  388. $Screenshots = array_map("trim", $Screenshots);
  389. $Screenshots = array_filter($Screenshots, function ($s) {
  390. return preg_match('/^'.IMAGE_REGEX.'$/i', $s);
  391. });
  392. $Screenshots = array_unique($Screenshots);
  393. $Screenshots = array_slice($Screenshots, 0, 10);
  394. if (!empty($Screenshots)) {
  395. $Screenshot = '';
  396. $DB->prepare_query("
  397. INSERT INTO torrents_screenshots
  398. (GroupID, UserID, Time, Image)
  399. VALUES (?, ?, NOW(), ?)", $GroupID, $LoggedUser['ID'], $Screenshot);
  400. foreach ($Screenshots as $Screenshot) {
  401. $DB->exec_prepared_query();
  402. }
  403. }
  404. } else {
  405. $DB->query("
  406. UPDATE torrents_group
  407. SET Time = NOW()
  408. WHERE ID = ?", $GroupID);
  409. $Cache->delete_value("torrent_group_$GroupID");
  410. $Cache->delete_value("torrents_details_$GroupID");
  411. $Cache->delete_value("detail_files_$GroupID");
  412. }
  413. // Description
  414. if (!isset($NoRevision) || !$NoRevision) {
  415. $DB->query("
  416. INSERT INTO wiki_torrents
  417. (PageID, Body, UserID, Summary, Time, Image)
  418. VALUES
  419. ( ?, ?, ?, 'Uploaded new torrent', NOW(), ? )", $GroupID, $T['GroupDescription'], $LoggedUser['ID'], $T['Image']);
  420. $RevisionID = $DB->inserted_id();
  421. // Revision ID
  422. $DB->query("
  423. UPDATE torrents_group
  424. SET RevisionID = ?
  425. WHERE ID = ?", $RevisionID, $GroupID);
  426. }
  427. // Tags
  428. $Tags = explode(',', $T['TagList']);
  429. if (!$T['GroupID']) {
  430. foreach ($Tags as $Tag) {
  431. $Tag = Misc::sanitize_tag($Tag);
  432. if (!empty($Tag)) {
  433. $Tag = Misc::get_alias_tag($Tag);
  434. $DB->query("
  435. INSERT INTO tags
  436. (Name, UserID)
  437. VALUES
  438. ( ?, ? )
  439. ON DUPLICATE KEY UPDATE
  440. Uses = Uses + 1;", $Tag, $LoggedUser['ID']);
  441. $TagID = $DB->inserted_id();
  442. $DB->query("
  443. INSERT INTO torrents_tags
  444. (TagID, GroupID, UserID)
  445. VALUES
  446. ( ?, ?, ? )
  447. ON DUPLICATE KEY UPDATE TagID=TagID", $TagID, $GroupID, $LoggedUser['ID']);
  448. }
  449. }
  450. }
  451. // Use this section to control freeleeches
  452. $T['FreeTorrent'] = '0';
  453. $T['FreeLeechType'] = '0';
  454. $DB->query("
  455. SELECT Name, First, Second
  456. FROM misc
  457. WHERE Second = 'freeleech'");
  458. if ($DB->has_results()) {
  459. $FreeLeechTags = $DB->to_array('Name');
  460. foreach ($FreeLeechTags as $Tag => $Exp) {
  461. if ($Tag === 'global' || in_array($Tag, $Tags)) {
  462. $T['FreeTorrent'] = '1';
  463. $T['FreeLeechType'] = '3';
  464. break;
  465. }
  466. }
  467. }
  468. // Movie and anime ISOs are neutral leech, and receive a BP bounty
  469. /*
  470. if (($Type === 'Movies' || $Type === 'Anime') && ($T['Container'] === 'ISO' || $T['Container'] === 'M2TS' || $T['Container'] === 'VOB IFO')) {
  471. $T['FreeTorrent'] = '2';
  472. $T['FreeLeechType'] = '2';
  473. }
  474. */
  475. // Torrent
  476. $DB->query(
  477. "
  478. INSERT INTO torrents
  479. (GroupID, UserID, Media, Container, Codec, Resolution,
  480. AudioFormat, Subbing, Language, Subber, Censored,
  481. Anonymous, Archive, info_hash, FileCount, FileList, FilePath, Size, Time,
  482. Description, MediaInfo, FreeTorrent, FreeLeechType)
  483. VALUES
  484. ( ?, ?, ?, ?, ?, ?,
  485. ?, ?, ?, ?, ?,
  486. ?, ?, ?, ?, ?, ?, ?, NOW(),
  487. ?, ?, ?, ? )",
  488. $GroupID,
  489. $LoggedUser['ID'],
  490. $T['Media'],
  491. $T['Container'],
  492. $T['Codec'],
  493. $T['Resolution'],
  494. $T['AudioFormat'],
  495. $T['Subbing'],
  496. $T['Language'],
  497. $T['Subber'],
  498. $T['Censored'],
  499. $T['Anonymous'],
  500. $T['Archive'],
  501. $InfoHash,
  502. $NumFiles,
  503. $FileString,
  504. $FilePath,
  505. $TotalSize,
  506. $T['TorrentDescription'],
  507. $T['MediaInfo'],
  508. $T['FreeTorrent'],
  509. $T['FreeLeechType']
  510. );
  511. $TorrentID = $DB->inserted_id();
  512. $Cache->increment('stats_torrent_count');
  513. $Tor->Dec['comment'] = 'https://'.SITE_DOMAIN.'/torrents.php?torrentid='.$TorrentID;
  514. Tracker::update_tracker('add_torrent', [
  515. 'id' => $TorrentID,
  516. 'info_hash' => rawurlencode($InfoHash),
  517. 'freetorrent' => $T['FreeTorrent']
  518. ]);
  519. $Debug->set_flag('upload: ocelot updated');
  520. // Prevent deletion of this torrent until the rest of the upload process is done
  521. // (expire the key after 10 minutes to prevent locking it for too long in case there's a fatal error below)
  522. $Cache->cache_value("torrent_{$TorrentID}_lock", true, 600);
  523. // Give BP if necessary
  524. if (($Type === "Movies" || $Type === "Anime") && ($T['Container'] === 'ISO' || $T['Container'] === 'M2TS' || $T['Container'] === 'VOB IFO')) {
  525. $BPAmt = (int) 2*($TotalSize / (1024*1024*1024))*1000;
  526. $DB->query("
  527. UPDATE users_main
  528. SET BonusPoints = BonusPoints + ?
  529. WHERE ID = ?", $BPAmt, $LoggedUser['ID']);
  530. $DB->query("
  531. UPDATE users_info
  532. SET AdminComment = CONCAT(NOW(), ' - Received $BPAmt ".BONUS_POINTS." for uploading a torrent $TorrentID\n\n', AdminComment)
  533. WHERE UserID = ?", $LoggedUser['ID']);
  534. $Cache->delete_value('user_info_heavy_'.$LoggedUser['ID']);
  535. $Cache->delete_value('user_stats_'.$LoggedUser['ID']);
  536. }
  537. // Add to shop freeleeches if necessary
  538. if ($T['FreeLeechType'] === 3) {
  539. // Figure out which duration to use
  540. $Expiry = 0;
  541. foreach ($FreeLeechTags as $Tag => $Exp) {
  542. if ($Tag === 'global' || in_array($Tag, $Tags)) {
  543. if (((int) $FreeLeechTags[$Tag]['First']) > $Expiry) {
  544. $Expiry = (int) $FreeLeechTags[$Tag]['First'];
  545. }
  546. }
  547. }
  548. if ($Expiry > 0) {
  549. $DB->query("
  550. INSERT INTO shop_freeleeches
  551. (TorrentID, ExpiryTime)
  552. VALUES
  553. (" . $TorrentID . ", FROM_UNIXTIME(" . $Expiry . "))
  554. ON DUPLICATE KEY UPDATE
  555. ExpiryTime = FROM_UNIXTIME(UNIX_TIMESTAMP(ExpiryTime) + ($Expiry - FROM_UNIXTIME(NOW())))");
  556. } else {
  557. Torrents::freeleech_torrents($TorrentID, 0, 0);
  558. }
  559. }
  560. //******************************************************************************//
  561. //--------------- Write torrent file -------------------------------------------//
  562. file_put_contents(TORRENT_STORE.$TorrentID.'.torrent', $Tor->encode());
  563. Misc::write_log("Torrent $TorrentID ($LogName) (".number_format($TotalSize / (1024 * 1024), 2).' MB) was uploaded by ' . $LoggedUser['Username']);
  564. Torrents::write_group_log($GroupID, $TorrentID, $LoggedUser['ID'], 'uploaded ('.number_format($TotalSize / (1024 * 1024), 2).' MB)', 0);
  565. Torrents::update_hash($GroupID);
  566. $Debug->set_flag('upload: sphinx updated');
  567. //******************************************************************************//
  568. //---------------------- Recent Uploads ----------------------------------------//
  569. if (trim($T['Image']) !== '') {
  570. $RecentUploads = $Cache->get_value("recent_uploads_$UserID");
  571. if (is_array($RecentUploads)) {
  572. do {
  573. foreach ($RecentUploads as $Item) {
  574. if ($Item['ID'] === $GroupID) {
  575. break 2;
  576. }
  577. }
  578. // Only reached if no matching GroupIDs in the cache already.
  579. if (count($RecentUploads) === 5) {
  580. array_pop($RecentUploads);
  581. }
  582. array_unshift($RecentUploads, array(
  583. 'ID' => $GroupID,
  584. 'Name' => trim($T['Title']),
  585. 'Artist' => Artists::display_artists($ArtistForm, false, true),
  586. 'WikiImage' => trim($T['Image'])));
  587. $Cache->cache_value("recent_uploads_$UserID", $RecentUploads, 0);
  588. } while (0);
  589. }
  590. }
  591. //******************************************************************************//
  592. //------------------------------- Post-processing ------------------------------//
  593. /* Because tracker updates and notifications can be slow, we're
  594. * redirecting the user to the destination page and flushing the buffers
  595. * to make it seem like the PHP process is working in the background.
  596. */
  597. if ($PublicTorrent) {
  598. View::show_header('Warning'); ?>
  599. <h1>Warning</h1>
  600. <p><strong>Your torrent has been uploaded - but you must re-download your torrent file from <a
  601. href="torrents.php?id=<?=$GroupID?>&torrentid=<?=$TorrentID?>">here</a>
  602. because the site modified it to make it private.</strong></p>
  603. <?php
  604. View::show_footer();
  605. } elseif ($UnsourcedTorrent) {
  606. View::show_header('Warning'); ?>
  607. <h1>Warning</h1>
  608. <p><strong>Your torrent has been uploaded - but you must re-download your torrent file from <a
  609. href="torrents.php?id=<?=$GroupID?>&torrentid=<?=$TorrentID?>">here</a>
  610. because the site modified it to add a source flag.</strong></p>
  611. <?php
  612. View::show_footer();
  613. } elseif ($RequestID) {
  614. header("Location: requests.php?action=takefill&requestid=$RequestID&torrentid=$TorrentID&auth=".$LoggedUser['AuthKey']);
  615. } else {
  616. header("Location: torrents.php?id=$GroupID&torrentid=$TorrentID");
  617. }
  618. if (function_exists('fastcgi_finish_request')) {
  619. fastcgi_finish_request();
  620. } else {
  621. ignore_user_abort(true);
  622. ob_flush();
  623. flush();
  624. ob_start(); // So we don't keep sending data to the client
  625. }
  626. //******************************************************************************//
  627. //--------------------------- IRC announce and feeds ---------------------------//
  628. $Announce = '';
  629. $Announce .= Artists::display_artists($ArtistForm, false);
  630. $Announce .= substr(trim(empty($T['Title']) ? (empty($T['TitleRJ']) ? $T['TitleJP'] : $T['TitleRJ']) : $T['Title']), 0, 100);
  631. $Announce .= ' ';
  632. if ($Type !== 'Other') {
  633. $Announce .= '['.Torrents::torrent_info($T, false, false, false).']';
  634. }
  635. $Title = '['.$T['CategoryName'].'] '.$Announce;
  636. $Announce = "$Title - ".site_url()."torrents.php?id=$GroupID / ".site_url()."torrents.php?action=download&id=$TorrentID";
  637. $Announce .= ' - '.trim($T['TagList']);
  638. // ENT_QUOTES is needed to decode single quotes/apostrophes
  639. send_irc('PRIVMSG '.BOT_ANNOUNCE_CHAN.' '.html_entity_decode($Announce, ENT_QUOTES));
  640. $Debug->set_flag('upload: announced on irc');
  641. // Manage notifications
  642. // For RSS
  643. $Item = $Feed->item($Title, Text::strip_bbcode($Body), 'torrents.php?action=download&amp;authkey=[[AUTHKEY]]&amp;torrent_pass=[[PASSKEY]]&amp;id='.$TorrentID, $Properties['Anonymous'] ? 'Anonymous' : $LoggedUser['Username'], 'torrents.php?id='.$GroupID, trim($T['TagList']));
  644. // Notifications
  645. $SQL = "
  646. SELECT unf.ID, unf.UserID, torrent_pass
  647. FROM users_notify_filters AS unf
  648. JOIN users_main AS um ON um.ID = unf.UserID
  649. WHERE um.Enabled = '1'";
  650. if (empty($ArtistsUnescaped)) {
  651. $ArtistsUnescaped = $ArtistForm;
  652. }
  653. if (!empty($ArtistsUnescaped)) {
  654. $ArtistNameList = [];
  655. $GuestArtistNameList = [];
  656. foreach ($ArtistsUnescaped as $Importance => $Artist) {
  657. $ArtistNameList[] = "Artists LIKE '%|".db_string(str_replace('\\', '\\\\', $Artist['name']), true)."|%'";
  658. }
  659. // Don't add notification if >2 main artists or if tracked artist isn't a main artist
  660. if (count($ArtistNameList) > 2 || $Artist['name'] === 'Various Artists') {
  661. $SQL .= " AND (ExcludeVA = '0' AND (";
  662. $SQL .= implode(' OR ', array_merge($ArtistNameList, $GuestArtistNameList));
  663. $SQL .= " OR Artists = '')) AND (";
  664. } else {
  665. $SQL .= " AND (";
  666. if (!empty($GuestArtistNameList)) {
  667. $SQL .= "(ExcludeVA = '0' AND (";
  668. $SQL .= implode(' OR ', $GuestArtistNameList);
  669. $SQL .= ')) OR ';
  670. }
  671. if (count($ArtistNameList) > 0) {
  672. $SQL .= implode(' OR ', $ArtistNameList);
  673. $SQL .= " OR ";
  674. }
  675. $SQL .= "Artists = '') AND (";
  676. }
  677. } else {
  678. $SQL .= "AND (Artists = '') AND (";
  679. }
  680. reset($Tags);
  681. $TagSQL = [];
  682. $NotTagSQL = [];
  683. foreach ($Tags as $Tag) {
  684. $TagSQL[] = " Tags LIKE '%|".db_string(trim($Tag))."|%' ";
  685. $NotTagSQL[] = " NotTags LIKE '%|".db_string(trim($Tag))."|%' ";
  686. }
  687. $TagSQL[] = "Tags = ''";
  688. $SQL .= implode(' OR ', $TagSQL);
  689. $SQL .= ") AND !(".implode(' OR ', $NotTagSQL).')';
  690. $SQL .= " AND (Categories LIKE '%|".db_string(trim($Type))."|%' OR Categories = '') ";
  691. if ($T['ReleaseType']) {
  692. $SQL .= " AND (ReleaseTypes LIKE '%|".db_string(trim($ReleaseTypes[$T['ReleaseType']]))."|%' OR ReleaseTypes = '') ";
  693. } else {
  694. $SQL .= " AND (ReleaseTypes = '') ";
  695. }
  696. /*
  697. Notify based on the following:
  698. 1. The torrent must match the formatbitrate filter on the notification
  699. 2. If they set NewGroupsOnly to 1, it must also be the first torrent in the group to match the formatbitrate filter on the notification
  700. */
  701. if ($T['Format']) {
  702. $SQL .= " AND (Formats LIKE '%|".db_string(trim($T['Format']))."|%' OR Formats = '') ";
  703. } else {
  704. $SQL .= " AND (Formats = '') ";
  705. }
  706. if ($_POST['bitrate']) {
  707. $SQL .= " AND (Encodings LIKE '%|".db_string(trim($_POST['bitrate']))."|%' OR Encodings = '') ";
  708. } else {
  709. $SQL .= " AND (Encodings = '') ";
  710. }
  711. if ($T['Media']) {
  712. $SQL .= " AND (Media LIKE '%|".db_string(trim($T['Media']))."|%' OR Media = '') ";
  713. } else {
  714. $SQL .= " AND (Media = '') ";
  715. }
  716. // Either they aren't using NewGroupsOnly
  717. $SQL .= "AND ((NewGroupsOnly = '0' ";
  718. // Or this is the first torrent in the group to match the formatbitrate filter
  719. $SQL .= ") OR ( NewGroupsOnly = '1' ";
  720. $SQL .= '))';
  721. if ($T['Year']) {
  722. $SQL .= " AND (('".db_string(trim($T['Year']))."' BETWEEN FromYear AND ToYear)
  723. OR (FromYear = 0 AND ToYear = 0)) ";
  724. } else {
  725. $SQL .= " AND (FromYear = 0 AND ToYear = 0) ";
  726. }
  727. $SQL .= " AND UserID !== '".$LoggedUser['ID']."' ";
  728. $DB->query("
  729. SELECT Paranoia
  730. FROM users_main
  731. WHERE ID = $LoggedUser[ID]");
  732. list($Paranoia) = $DB->next_record();
  733. $Paranoia = unserialize($Paranoia);
  734. if (!is_array($Paranoia)) {
  735. $Paranoia = [];
  736. }
  737. if (!in_array('notifications', $Paranoia)) {
  738. $SQL .= " AND (Users LIKE '%|".$LoggedUser['ID']."|%' OR Users = '') ";
  739. }
  740. $SQL .= " AND UserID !== '".$LoggedUser['ID']."' ";
  741. $DB->query($SQL);
  742. $Debug->set_flag('upload: notification query finished');
  743. if ($DB->has_results()) {
  744. $UserArray = $DB->to_array('UserID');
  745. $FilterArray = $DB->to_array('ID');
  746. $InsertSQL = '
  747. INSERT IGNORE INTO users_notify_torrents (UserID, GroupID, TorrentID, FilterID)
  748. VALUES ';
  749. $Rows = [];
  750. foreach ($UserArray as $User) {
  751. list($FilterID, $UserID, $Passkey) = $User;
  752. $Rows[] = "('$UserID', '$GroupID', '$TorrentID', '$FilterID')";
  753. $Feed->populate("torrents_notify_$Passkey", $Item);
  754. $Cache->delete_value("notifications_new_$UserID");
  755. }
  756. $InsertSQL .= implode(',', $Rows);
  757. $DB->query($InsertSQL);
  758. $Debug->set_flag('upload: notification inserts finished');
  759. foreach ($FilterArray as $Filter) {
  760. list($FilterID, $UserID, $Passkey) = $Filter;
  761. $Feed->populate("torrents_notify_{$FilterID}_$Passkey", $Item);
  762. }
  763. }
  764. // RSS for bookmarks
  765. $DB->query("
  766. SELECT u.ID, u.torrent_pass
  767. FROM users_main AS u
  768. JOIN bookmarks_torrents AS b ON b.UserID = u.ID
  769. WHERE b.GroupID = $GroupID");
  770. while (list($UserID, $Passkey) = $DB->next_record()) {
  771. $Feed->populate("torrents_bookmarks_t_$Passkey", $Item);
  772. }
  773. $Feed->populate('torrents_all', $Item);
  774. $Feed->populate('torrents_'.strtolower($Type), $Item);
  775. $Debug->set_flag('upload: notifications handled');
  776. // Clear cache
  777. $Cache->delete_value("torrents_details_$GroupID");
  778. $Cache->delete_value("contest_scores");
  779. // Allow deletion of this torrent now
  780. $Cache->delete_value("torrent_{$TorrentID}_lock");