Skip to content

Commit 9b3342a

Browse files
Fixes Forum Threading, RSS-Feeds, and Threads-sorting
1 parent 4809da5 commit 9b3342a

1 file changed

Lines changed: 111 additions & 83 deletions

File tree

www/includes/forum.inc.php

Lines changed: 111 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,11 +1705,12 @@ static function getSortlink($order) {
17051705
*
17061706
* @author [z]biko
17071707
* @author IneX
1708-
* @version 3.1
1708+
* @version 3.2
17091709
* @since 1.0 method added
17101710
* @since 2.0 `07.11.2018` `IneX` code optimizations, fixed $sql-Query for Thread list for not-loggedin Users
17111711
* @since 3.0 `05.12.2018` `IneX` fixed and restored Thread-Overview Pagination
17121712
* @since 3.1 `25.07.2019` `IneX` fixed Bug #774: In der Forumthreads-Übersicht wird ein falscher "Thread starter" angezeigt
1713+
* @since 3.2 `20.01.2024` `IneX` fixes SQL nonaggregated column warning, convert SQL to prepared statement
17131714
*
17141715
* @used-by Forum::getNavigation()
17151716
* @param array|string $showboards Array mit den Boards für welche die Threads angezeigt werden sollen
@@ -1719,94 +1720,113 @@ static function getSortlink($order) {
17191720
* @global object $user Globales Class-Object mit den User-Methoden & Variablen
17201721
* @return string
17211722
*/
1722-
static function getHTML($showboards, $pagesize, $sortby='last_post_date')
1723+
static function getHTML($showboards, $pagesize, $sortby='threadupdated')
17231724
{
17241725
global $db, $user;
17251726

1727+
$sqlparams = [];
1728+
$showboards_values = [];
1729+
17261730
/** Boards als komma-separierte Liste */
1727-
if (is_array($showboards)) $showboards_commaseparated = sprintf('"%s"', implode('","', $showboards));
1728-
else $showboards_commaseparated = '"'.$showboards.'"';
1731+
$sqlplaceholders_boards = null;
1732+
if (is_array($showboards)) {
1733+
$sqlplaceholders_boards = implode(',', array_fill(0, count($showboards), '?'));
1734+
$showboards_values = array_map('strval', $showboards); // Each board must be a string
1735+
}
1736+
else {
1737+
$sqlplaceholders_boards = '?';
1738+
$showboards_values[] = strval($showboards);
1739+
}
17291740

1730-
/** Sortieren */
1731-
if(empty($sortby) || is_numeric($sortby) || is_array($sortby)) $sortby = 'last_post_date';
1741+
/** Sortierungsspalte */
1742+
if (!is_string($sortby)) $sortby = 'threadupdated';
1743+
$sqlsortby_value = 'last_post_date';
1744+
switch ($sortby) {
1745+
case 'threadname':
1746+
$sqlsortby_value = 't.text';
1747+
break;
1748+
case 'threadstarter':
1749+
$sqlsortby_value = 'thread_starter';
1750+
break;
1751+
case 'threadid':
1752+
$sqlsortby_value = 'ct.thread_id';
1753+
break;
1754+
case 'threadposts':
1755+
$sqlsortby_value = 'numposts';
1756+
break;
1757+
default: // + Fallback
1758+
$sqlsortby_value = 'last_post_date';
1759+
break;
1760+
}
17321761

1733-
/**
1734-
* "ASC"-Sortierung ist nur bei Nummern oder Datum erlaubt, nicht bei Text
1735-
* ...prüfen, ob wir eine numerische/datum Spalte sortieren wollen */
1736-
$order = 'DESC';
1737-
$new_order = 'ASC';
1738-
if (strpos($sortby,'_id') > 0 || strpos($sortby,'date') > 0 || strpos($sortby,'num') > 0)
1739-
{
1740-
if(isset($_GET['order'])) {
1741-
switch ($_GET['order']) {
1742-
case 'ASC':
1743-
$order = 'ASC';
1744-
$new_order = 'DESC';
1745-
break;
1746-
case 'DESC':
1747-
$order = 'DESC';
1748-
$new_order = 'ASC';
1749-
break;
1750-
default:
1751-
$order = 'DESC';
1752-
$new_order = 'ASC';
1753-
}
1754-
}
1762+
/** Sortierreihenfolge (ASC / DESC) */
1763+
$orders = [ 1 => 'DESC', 2 => 'ASC'];
1764+
$sqlorderby_value = $orders[1];
1765+
$new_order = 2;
1766+
$custom_order = (isset($_GET['order']) && key_exists(intval($_GET['order']), $orders) ? $orders[intval($_GET['order'])] : $orders[1]); // FIXME function param
1767+
if($custom_order === $orders[2]) {
1768+
$sqlorderby_value = $orders[2];
1769+
$new_order = 1;
17551770
}
17561771

17571772
/** Threads analog ?page=n anzeigen... */
1758-
$page = (!isset($_GET['page']) || empty($_GET['page']) || !is_numeric($_GET['page'])) ? 1 : $_GET['page'];
1759-
$limit = ($page-1) * $pagesize.','.$pagesize;
1773+
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT) ?? 1; // FIXME function param
1774+
$sqlrecordsnum_value = intval($pagesize);
1775+
$sqlrecordsstart_value = (($page-1) * $sqlrecordsnum_value);
17601776

17611777
/** Query for Thread list */
1762-
$sql = 'SELECT
1763-
c.board board,
1764-
max(c.id) id,
1765-
max(c.parent_id) parent_id,
1766-
c.text last_post_text,
1767-
max(c.user_id) last_comment_poster,
1768-
UNIX_TIMESTAMP(c.date) last_post_date,
1769-
max(t.thread_id) thread_id,
1770-
max(t.user_id) thread_starter,
1771-
UNIX_TIMESTAMP(t.date) thread_date,
1772-
'.($user->is_loggedin() ? 'IF(ISNULL(max(tfav.thread_id) ), 0, 1) isfavorite,
1773-
IF(ISNULL(max(tignore.thread_id)), 0, 1) ignoreit,' : '').'
1774-
count(DISTINCT cnum.id) numposts,
1775-
(SELECT count(DISTINCT thread_id) FROM comments WHERE board IN ('.$showboards_commaseparated.')) numthreads
1776-
FROM
1777-
comments_threads ct
1778-
LEFT JOIN comments c ON (c.id = (SELECT MAX(id) FROM comments WHERE thread_id = ct.thread_id AND board = ct.board) )
1778+
$sql = 'SELECT c.board board,
1779+
MAX(c.id) id,
1780+
MAX(c.parent_id) parent_id,
1781+
(SELECT MAX(text) FROM comments AS sub_c WHERE sub_c.id = MAX(c.id) GROUP BY sub_c.board, sub_c.thread_id) AS last_post_text,
1782+
(SELECT user_id FROM comments AS sub_c WHERE sub_c.id = MAX(c.id) GROUP BY sub_c.board, sub_c.thread_id) AS last_comment_poster,
1783+
UNIX_TIMESTAMP(MAX(c.date)) last_post_date,
1784+
MAX(t.thread_id) thread_id,
1785+
MAX(t.user_id) thread_starter,
1786+
UNIX_TIMESTAMP(MAX(t.date)) thread_date,'.
1787+
($user->is_loggedin() ? 'IF(ISNULL(MAX(tfav.thread_id)), 0, 1) isfavorite, IF(ISNULL(MAX(tignore.thread_id)), 0, 1) ignoreit,' : '')
1788+
.'COUNT(DISTINCT cnum.id) numposts,
1789+
(SELECT COUNT(DISTINCT thread_id) FROM comments WHERE board IN ('.$sqlplaceholders_boards.')) numthreads
1790+
FROM comments_threads ct
1791+
LEFT JOIN (SELECT MAX(id) id, board, user_id, parent_id, date FROM comments GROUP BY board, thread_id, parent_id, date, user_id) c ON (c.id = ct.comment_id)
17791792
LEFT JOIN comments t ON (t.id = ct.comment_id)
1780-
LEFT JOIN comments cnum ON (ct.board = cnum.board AND ct.thread_id = cnum.thread_id)
1781-
'.($user->is_loggedin() ? 'LEFT JOIN comments_threads_rights ctr
1782-
ON (ctr.thread_id=ct.thread_id AND ctr.board=ct.board AND ctr.user_id='.$user->id.')
1793+
LEFT JOIN comments cnum ON (ct.board = cnum.board AND ct.thread_id = cnum.thread_id)'.
1794+
($user->is_loggedin() ? 'LEFT JOIN comments_threads_rights ctr
1795+
ON (ctr.thread_id=ct.thread_id AND ctr.board=ct.board AND ctr.user_id=?)
17831796
LEFT JOIN comments_threads_favorites tfav
1784-
ON (tfav.board = ct.board AND tfav.thread_id = ct.thread_id AND tfav.user_id='.$user->id.')
1797+
ON (tfav.board = ct.board AND tfav.thread_id = ct.thread_id AND tfav.user_id=?)
17851798
LEFT JOIN comments_threads_ignore tignore
1786-
ON (tignore.board = ct.board AND tignore.thread_id = ct.thread_id AND tignore.user_id='.$user->id.')
1787-
' : '').'
1788-
WHERE
1789-
c.board IN ('.$showboards_commaseparated.')
1790-
AND ('.$user->typ.' >= ct.rights OR ct.rights='.USER_SPECIAL . ($user->is_loggedin() ? ' AND ctr.user_id IS NOT NULL' : '').')
1791-
AND ct.comment_id IS NOT NULL
1792-
GROUP BY
1793-
c.board, ct.thread_id, t.date, c.date, c.text
1794-
ORDER BY '.$sortby.' '.$order.'
1795-
LIMIT '.$limit
1796-
;
1797-
$result = $db->query($sql, __FILE__, __LINE__, __METHOD__);
1799+
ON (tignore.board = ct.board AND tignore.thread_id = ct.thread_id AND tignore.user_id=?)' : '')
1800+
.'WHERE
1801+
c.board IN ('.$sqlplaceholders_boards.')
1802+
AND (ct.rights<=? OR ct.rights=?'.($user->is_loggedin() ? ' AND ctr.user_id IS NOT NULL' : '').')
1803+
AND ct.comment_id IS NOT NULL
1804+
GROUP BY c.board, ct.thread_id, t.text
1805+
ORDER BY '.$sqlsortby_value.' '.$sqlorderby_value.' LIMIT ?,?';
1806+
$sqlparams = array_merge($sqlparams, $showboards_values);
1807+
if ($user->is_loggedin()) {
1808+
$sqlparams[] = $user->id;
1809+
$sqlparams[] = $user->id;
1810+
$sqlparams[] = $user->id;
1811+
}
1812+
$sqlparams = array_merge($sqlparams, $showboards_values);
1813+
$sqlparams[] = $user->typ;
1814+
$sqlparams[] = USER_SPECIAL;
1815+
$sqlparams[] = $sqlrecordsstart_value;
1816+
$sqlparams[] = $sqlrecordsnum_value;
1817+
$result = $db->query($sql, __FILE__, __LINE__, __METHOD__, $sqlparams);
17981818

17991819
/** Ausgabe ---------------------------------------------------------------- */
18001820
/** Thread-Table mit Spaltenüberschriften */
18011821
$html =
18021822
'<h1>Discussions</h1>'
1803-
.'<table cellpadding="1" cellspacing="1" class="border" width="100%">'
1823+
.'<table cellpadding="1" cellspacing="1" class="border">'
18041824
.'<!--googleoff: all--><tr class="title">'
1805-
.'<td align="left" width="30%"><a href="?sortby=t.text&amp;order='.$new_order.'">Thread</a></td>'
1806-
.'<td align="left" class="small hide-mobile" width="11%"><a href="?sortby=tu_username&amp;order='.$new_order.'">Thread starter</a></td>'
1807-
.'<td align="center" class="hide-mobile"><a href="?sortby=ct.thread_id&amp;order='.$new_order.'">Datum</a></td>'
1808-
.'<td align="center" class="small hide-mobile"><a href="?sortby=numposts&amp;order='.$new_order.'">#</a></td>'
1809-
.'<td align="left" class="small" width="25%"><a href="?sortby=last_post_date&amp;order='.$new_order.'">Last comment</a></td>'
1825+
.'<td align="left" width="30%"><a href="?sortby=threadname&amp;order='.$new_order.'">Thread</a></td>'
1826+
.'<td align="left" class="small hide-mobile" width="11%"><a href="?sortby=threadstarter&amp;order='.$new_order.'">Thread starter</a></td>'
1827+
.'<td align="center" class="hide-mobile"><a href="?sortby=threadid&amp;order='.$new_order.'">Datum</a></td>'
1828+
.'<td align="center" class="small hide-mobile"><a href="?sortby=threadposts&amp;order='.$new_order.'">#</a></td>'
1829+
.'<td align="left" class="small" width="25%"><a href="?sortby=threadupdated&amp;order='.$new_order.'">Last comment</a></td>'
18101830
.'<td class="hide-mobile"></td>'
18111831
.'</tr><!--googleon: all-->';
18121832

@@ -1836,7 +1856,11 @@ static function getHTML($showboards, $pagesize, $sortby='last_post_date')
18361856
.Comment::getLinkThread($rs['board'], $rs['thread_id'])
18371857
.'</span>';
18381858

1839-
/** DISABLED
1859+
/**
1860+
* Sticky-Threads.
1861+
* @link https://zorg.ch/bug/158 Sticky Threads
1862+
*/
1863+
/** // TODO
18401864
if($rs['sticky'] == 1) {
18411865
if($user->typ >= USER_MEMBER) {
18421866
$html .= ' <a href="/actions/forum.php?action=unsticky&thread_id='.$rs['thread_id'].'">*sticky*</a>';
@@ -1913,7 +1937,7 @@ static function getHTML($showboards, $pagesize, $sortby='last_post_date')
19131937
;
19141938
$html .= '</tr>';
19151939

1916-
$numpages = $rs['numthreads'];
1940+
$numpages = $rs['numthreads']; // FIXME numthreads unterschlägt Thread-Pages am Ende! z.B. last=155 - aber via URL kann man weiterb blättern...
19171941
}
19181942

19191943
/** Pagination für Thread-Liste */
@@ -1977,12 +2001,13 @@ static function hasPostedRecently($user_id, $parent_id) {
19772001
*
19782002
* @link https://github.com/zorgch/zorg-code/blob/master/www/templates/layout/partials/commentform.tpl Template used for output is commentform.tpl
19792003
*
1980-
* @version 3.2
2004+
* @version 3.5
19812005
* @since 1.0 `[z]biko` added method
19822006
* @since 2.0 `17.12.2017` `IneX` Deprecated Forum::getFormNewPart2of2() & 'tpl:194' due to change into a Smary-Template 'file:commentform.tpl'
19832007
* @since 3.0 `25.07.2018` `IneX` Updated SQL-Queries, Formatting & check for logged in User regarding printing Subscriptions & Unreads
19842008
* @since 3.1 `22.01.2020` `IneX` Code optimizations
19852009
* @since 3.2 `22.01.2020` `IneX` Fixed PHP Notice undefined property: usersystem::$id
2010+
* @since 3.5 `21.01.2024` `IneX` Fixed Comments Threading in Boards, updated SQL to use prepared statements
19862011
*
19872012
* @uses USER_USER
19882013
* @uses usersystem::is_loggedin()
@@ -2000,9 +2025,14 @@ static function printCommentingSystem($board, $thread_id)
20002025
{
20012026
global $db, $user, $smarty;
20022027

2028+
/** Validate parameters */
2029+
$board = strval($board);
2030+
$thread_id = intval($thread_id);
2031+
20032032
/** Get and set missing parent_id */
20042033
// FIXME it would be better to pass $_GET[parent_id] als Function Param via {smarty_comments}-Parameter...
2005-
$parent_id = filter_input(INPUT_GET, 'parent_id', FILTER_VALIDATE_INT) ?? intval($thread_id);
2034+
$parent_id = filter_input(INPUT_GET, 'parent_id', FILTER_VALIDATE_INT) ?? $thread_id;
2035+
zorgDebugger::log()->debug('thread_id: %d | parent_id: %d', [$thread_id, $parent_id]);
20062036

20072037
if (true === Thread::hasRights($board, $thread_id, ($user->is_loggedin() ? $user->id : USER_ALLE)))
20082038
{
@@ -2012,14 +2042,14 @@ static function printCommentingSystem($board, $thread_id)
20122042
/** Subscribed_Comments Array Bauen (nur für eingeloggte User) */
20132043
if($user->is_loggedin())
20142044
{
2015-
$comments_subscribed = array();
2045+
$comments_subscribed = [];
20162046
$sql = 'SELECT comment_id FROM comments_subscriptions WHERE board=? AND user_id=?';
20172047
$e = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$board, $user->id]);
20182048
while ($d = $db->fetch($e)) $comments_subscribed[] = $d['comment_id'];
20192049
$smarty->assign('comments_subscribed', $comments_subscribed);
20202050

20212051
/** Unread Comment Array Bauen */
2022-
$comments_unread = array();
2052+
$comments_unread = [];
20232053
$sql = 'SELECT u.* FROM comments_unread u, comments c WHERE c.id=u.comment_id AND c.thread_id=? AND c.board=? AND u.user_id=?';
20242054
$e = $db->query($sql, __FILE__, __LINE__, __METHOD__, [$thread_id, $board, $user->id]);
20252055
while ($d = $db->fetch($e)) $comments_unread[] = $d['comment_id'];
@@ -2031,14 +2061,13 @@ static function printCommentingSystem($board, $thread_id)
20312061
$d = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__, [$board, $parent_id]));
20322062

20332063
/** Set Thread/Sub-Thread starting Comment-ID */
2034-
$comment_parent_id = (isset($d['parent_id']) && $d['parent_id'] > 0 ? intval($d['parent_id']) : $thread_id);
2064+
$comment_parent_id = (isset($d['parent_id']) ? intval($d['parent_id']) : $thread_id);
20352065

20362066
/** Comments an Smarty übergeben */
2037-
if ($parent_id === $thread_id || $thread_id === $comment_parent_id)
2067+
if ($parent_id === $thread_id || $comment_parent_id === $thread_id)
20382068
{
20392069
/** $thread_id ist der erste Comment (Thread) */
2040-
$fetch_commentthread = sprintf('comments:%s-%d', $board, $thread_id);
2041-
$smarty->display($fetch_commentthread);
2070+
$smarty->display('comments:'.$board.'-'.$thread_id);
20422071
} else {
20432072
/** $thread_id ist ein Sub-Thread (nicht Main Thread) */
20442073
$smarty->assign('comments_top_additional', 1);
@@ -2050,7 +2079,7 @@ static function printCommentingSystem($board, $thread_id)
20502079
{
20512080
$smarty->assign('board', $board);
20522081
$smarty->assign('thread_id', $thread_id);
2053-
$smarty->assign('parent_id', $comment_parent_id);
2082+
$smarty->assign('parent_id', $comment_parent_id); // parent_id darf nie leer sein! Sonst crasht nachher das Commenting
20542083
$smarty->display('file:layout/partials/commentform.tpl');
20552084
}
20562085
}
@@ -2153,8 +2182,7 @@ static function printRSS($board='f', $user_id=null, $thread_id=null)
21532182
// für den Moment wird hier einfach ein Query über alle neuen Sachen gemacht.... IneX, 16.3.08
21542183
// FIXME erm... aber so wies scheint, kommen die richtigen Sachen (weil alles über s board gesteuert wird). IneX, 16.3.08
21552184
$sql ='SELECT comments.*, IF(ISNULL(comments_unread.comment_id), 0, 1) AS isunread, UNIX_TIMESTAMP(date) as date
2156-
FROM comments LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id = ?) '.( !empty($wboard) ? 'WHERE '.$wboard : '').
2157-
' ORDER BY date desc LIMIT ?';
2185+
FROM comments LEFT JOIN comments_unread ON (comments.id=comments_unread.comment_id AND comments_unread.user_id = ?) '.( !empty($wboard) ? 'WHERE '.$wboard : '').' ORDER BY date desc LIMIT ?'; // FIXME https://zorg.ch/index.php?tpl=162&id=2
21582186
$sqlparams[] = $user->id;
21592187
if (!empty($wboard)) $sqlparams[] = $board;
21602188
$sqlparams[] = $num;
@@ -2164,7 +2192,7 @@ static function printRSS($board='f', $user_id=null, $thread_id=null)
21642192
/**
21652193
* Feed bauen - Query mit $sql
21662194
*/
2167-
if ($result = $db->query($sql, __FILE__, __LINE__, __METHOD__))
2195+
if ($result = $db->query($sql, __FILE__, __LINE__, __METHOD__, $sqlparams))
21682196
{
21692197
/** Datensätze auslesen */
21702198
while($rs = $db->fetch($result))

0 commit comments

Comments
 (0)