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.

thread.php 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. #declare(strict_types=1);
  3. # todo: Go through line by line
  4. // todo: Normalize thread_*_info don't need to waste all that ram on things that are already in other caches
  5. /**********|| Page to show individual threads || ********************************\
  6. Things to expect in $_GET:
  7. ThreadID: ID of the forum curently being browsed
  8. page: The page the user's on.
  9. page = 1 is the same as no page
  10. ********************************************************************************/
  11. //---------- Things to sort out before it can start printing/generating content
  12. // Check for lame SQL injection attempts
  13. if (!isset($_GET['threadid']) || !is_number($_GET['threadid'])) {
  14. if (isset($_GET['topicid']) && is_number($_GET['topicid'])) {
  15. $ThreadID = $_GET['topicid'];
  16. } elseif (isset($_GET['postid']) && is_number($_GET['postid'])) {
  17. $DB->query("
  18. SELECT TopicID
  19. FROM forums_posts
  20. WHERE ID = $_GET[postid]");
  21. list($ThreadID) = $DB->next_record();
  22. if ($ThreadID) {
  23. // Redirect postid to threadid when necessary
  24. header("Location: ajax.php?action=forum&type=viewthread&threadid=$ThreadID&postid=$_GET[postid]");
  25. error();
  26. } else {
  27. echo json_encode(array('status' => 'failure'));
  28. error();
  29. }
  30. } else {
  31. echo json_encode(array('status' => 'failure'));
  32. error();
  33. }
  34. } else {
  35. $ThreadID = $_GET['threadid'];
  36. }
  37. if (isset($_GET['pp'])) {
  38. $PerPage = $_GET['pp'];
  39. } elseif (isset($LoggedUser['PostsPerPage'])) {
  40. $PerPage = $LoggedUser['PostsPerPage'];
  41. } else {
  42. $PerPage = POSTS_PER_PAGE;
  43. }
  44. //---------- Get some data to start processing
  45. // Thread information, constant across all pages
  46. $ThreadInfo = Forums::get_thread_info($ThreadID, true, true);
  47. if ($ThreadInfo === null) {
  48. json_die('failure', 'no such thread exists');
  49. }
  50. $ForumID = $ThreadInfo['ForumID'];
  51. // Make sure they're allowed to look at the page
  52. if (!Forums::check_forumperm($ForumID)) {
  53. echo json_encode(array('status' => 'failure'));
  54. error();
  55. }
  56. // Post links utilize the catalogue & key params to prevent issues with custom posts per page
  57. if ($ThreadInfo['Posts'] > $PerPage) {
  58. if (isset($_GET['post']) && is_number($_GET['post'])) {
  59. $PostNum = $_GET['post'];
  60. } elseif (isset($_GET['postid']) && is_number($_GET['postid'])) {
  61. $DB->query("
  62. SELECT COUNT(ID)
  63. FROM forums_posts
  64. WHERE TopicID = $ThreadID
  65. AND ID <= $_GET[postid]");
  66. list($PostNum) = $DB->next_record();
  67. } else {
  68. $PostNum = 1;
  69. }
  70. } else {
  71. $PostNum = 1;
  72. }
  73. list($Page, $Limit) = Format::page_limit($PerPage, min($ThreadInfo['Posts'], $PostNum));
  74. if (($Page - 1) * $PerPage > $ThreadInfo['Posts']) {
  75. $Page = ceil($ThreadInfo['Posts'] / $PerPage);
  76. }
  77. list($CatalogueID, $CatalogueLimit) = Format::catalogue_limit($Page, $PerPage, THREAD_CATALOGUE);
  78. // Cache catalogue from which the page is selected, allows block caches and future ability to specify posts per page
  79. if (!$Catalogue = $Cache->get_value("thread_$ThreadID"."_catalogue_$CatalogueID")) {
  80. $DB->query("
  81. SELECT
  82. p.ID,
  83. p.AuthorID,
  84. p.AddedTime,
  85. p.Body,
  86. p.EditedUserID,
  87. p.EditedTime
  88. FROM forums_posts AS p
  89. WHERE p.TopicID = '$ThreadID'
  90. AND p.ID != '".$ThreadInfo['StickyPostID']."'
  91. LIMIT $CatalogueLimit");
  92. $Catalogue = $DB->to_array(false, MYSQLI_ASSOC);
  93. if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
  94. $Cache->cache_value("thread_$ThreadID"."_catalogue_$CatalogueID", $Catalogue, 0);
  95. }
  96. }
  97. $Thread = Format::catalogue_select($Catalogue, $Page, $PerPage, THREAD_CATALOGUE);
  98. if ($_GET['updatelastread'] !== '0') {
  99. $LastPost = end($Thread);
  100. $LastPost = $LastPost['ID'];
  101. reset($Thread);
  102. if ($ThreadInfo['Posts'] <= $PerPage * $Page && $ThreadInfo['StickyPostID'] > $LastPost) {
  103. $LastPost = $ThreadInfo['StickyPostID'];
  104. }
  105. // Handle last read
  106. if (!$ThreadInfo['IsLocked'] || $ThreadInfo['IsSticky']) {
  107. $DB->query("
  108. SELECT PostID
  109. FROM forums_last_read_topics
  110. WHERE UserID = '$LoggedUser[ID]'
  111. AND TopicID = '$ThreadID'");
  112. list($LastRead) = $DB->next_record();
  113. if ($LastRead < $LastPost) {
  114. $DB->query("
  115. INSERT INTO forums_last_read_topics
  116. (UserID, TopicID, PostID)
  117. VALUES
  118. ('$LoggedUser[ID]', '$ThreadID', '".db_string($LastPost)."')
  119. ON DUPLICATE KEY UPDATE
  120. PostID = '$LastPost'");
  121. }
  122. }
  123. }
  124. // Handle subscriptions
  125. $UserSubscriptions = Subscriptions::get_subscriptions();
  126. if (empty($UserSubscriptions)) {
  127. $UserSubscriptions = [];
  128. }
  129. if (in_array($ThreadID, $UserSubscriptions)) {
  130. $Cache->delete_value('subscriptions_user_new_'.$LoggedUser['ID']);
  131. }
  132. $JsonPoll = [];
  133. if ($ThreadInfo['NoPoll'] === 0) {
  134. if (!list($Question, $Answers, $Votes, $Featured, $Closed) = $Cache->get_value("polls_$ThreadID")) {
  135. $DB->query("
  136. SELECT Question, Answers, Featured, Closed
  137. FROM forums_polls
  138. WHERE TopicID = '$ThreadID'");
  139. list($Question, $Answers, $Featured, $Closed) = $DB->next_record(MYSQLI_NUM, array(1));
  140. $Answers = unserialize($Answers);
  141. $DB->query("
  142. SELECT Vote, COUNT(UserID)
  143. FROM forums_polls_votes
  144. WHERE TopicID = '$ThreadID'
  145. GROUP BY Vote");
  146. $VoteArray = $DB->to_array(false, MYSQLI_NUM);
  147. $Votes = [];
  148. foreach ($VoteArray as $VoteSet) {
  149. list($Key, $Value) = $VoteSet;
  150. $Votes[$Key] = $Value;
  151. }
  152. foreach (array_keys($Answers) as $i) {
  153. if (!isset($Votes[$i])) {
  154. $Votes[$i] = 0;
  155. }
  156. }
  157. $Cache->cache_value("polls_$ThreadID", array($Question, $Answers, $Votes, $Featured, $Closed), 0);
  158. }
  159. if (!empty($Votes)) {
  160. $TotalVotes = array_sum($Votes);
  161. $MaxVotes = max($Votes);
  162. } else {
  163. $TotalVotes = 0;
  164. $MaxVotes = 0;
  165. }
  166. #$RevealVoters = in_array($ForumID, FORUMS_TO_REVEAL_VOTERS);
  167. // Polls lose the you voted arrow thingy
  168. $DB->query("
  169. SELECT Vote
  170. FROM forums_polls_votes
  171. WHERE UserID = '".$LoggedUser['ID']."'
  172. AND TopicID = '$ThreadID'");
  173. list($UserResponse) = $DB->next_record();
  174. if (!empty($UserResponse) && $UserResponse !== 0) {
  175. $Answers[$UserResponse] = '&rsaquo; '.$Answers[$UserResponse];
  176. } /* else {
  177. if (!empty($UserResponse) && $RevealVoters) {
  178. $Answers[$UserResponse] = '&rsaquo; '.$Answers[$UserResponse];
  179. }
  180. }
  181. */
  182. $JsonPoll['closed'] = ($Closed === 1);
  183. $JsonPoll['featured'] = $Featured;
  184. $JsonPoll['question'] = $Question;
  185. $JsonPoll['maxVotes'] = (int)$MaxVotes;
  186. $JsonPoll['totalVotes'] = $TotalVotes;
  187. $JsonPollAnswers = [];
  188. foreach ($Answers as $i => $Answer) {
  189. if (!empty($Votes[$i]) && $TotalVotes > 0) {
  190. $Ratio = $Votes[$i] / $MaxVotes;
  191. $Percent = $Votes[$i] / $TotalVotes;
  192. } else {
  193. $Ratio = 0;
  194. $Percent = 0;
  195. }
  196. $JsonPollAnswers[] = array(
  197. 'answer' => $Answer,
  198. 'ratio' => $Ratio,
  199. 'percent' => $Percent
  200. );
  201. }
  202. if ($UserResponse !== null || $Closed || $ThreadInfo['IsLocked'] || $LoggedUser['Class'] < $Forums[$ForumID]['MinClassWrite']) {
  203. $JsonPoll['voted'] = true;
  204. } else {
  205. $JsonPoll['voted'] = false;
  206. }
  207. $JsonPoll['answers'] = $JsonPollAnswers;
  208. }
  209. // Sqeeze in stickypost
  210. if ($ThreadInfo['StickyPostID']) {
  211. if ($ThreadInfo['StickyPostID'] !== $Thread[0]['ID']) {
  212. array_unshift($Thread, $ThreadInfo['StickyPost']);
  213. }
  214. if ($ThreadInfo['StickyPostID'] !== $Thread[count($Thread) - 1]['ID']) {
  215. $Thread[] = $ThreadInfo['StickyPost'];
  216. }
  217. }
  218. $JsonPosts = [];
  219. foreach ($Thread as $Key => $Post) {
  220. list($PostID, $AuthorID, $AddedTime, $Body, $EditedUserID, $EditedTime) = array_values($Post);
  221. list($AuthorID, $Username, $PermissionID, $Paranoia, $Artist, $Donor, $Warned, $Avatar, $Enabled, $UserTitle) = array_values(Users::user_info($AuthorID));
  222. $UserInfo = Users::user_info($EditedUserID);
  223. $JsonPosts[] = [
  224. 'postId' => (int)$PostID,
  225. 'addedTime' => $AddedTime,
  226. 'bbBody' => $Body,
  227. 'body' => Text::full_format($Body),
  228. 'editedUserId' => (int)$EditedUserID,
  229. 'editedTime' => $EditedTime,
  230. 'editedUsername' => $UserInfo['Username'],
  231. 'author' => [
  232. 'authorId' => (int)$AuthorID,
  233. 'authorName' => $Username,
  234. 'paranoia' => $Paranoia,
  235. 'artist' => $Artist === '1',
  236. 'donor' => $Donor === '1',
  237. 'warned' => (bool)$Warned,
  238. 'avatar' => $Avatar,
  239. 'enabled' => $Enabled === '2' ? false : true,
  240. 'userTitle' => $UserTitle
  241. ]
  242. ];
  243. }
  244. echo json_encode([
  245. 'status' => 'success',
  246. 'response' => [
  247. 'forumId' => (int)$ForumID,
  248. 'forumName' => $Forums[$ForumID]['Name'],
  249. 'threadId' => (int)$ThreadID,
  250. 'threadTitle' => display_str($ThreadInfo['Title']),
  251. 'subscribed' => in_array($ThreadID, $UserSubscriptions),
  252. 'locked' => $ThreadInfo['IsLocked'] === 1,
  253. 'sticky' => $ThreadInfo['IsSticky'] === 1,
  254. 'currentPage' => (int)$Page,
  255. 'pages' => ceil($ThreadInfo['Posts'] / $PerPage),
  256. 'poll' => empty($JsonPoll) ? null : $JsonPoll,
  257. 'posts' => $JsonPosts
  258. ]
  259. ]);