@@ -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 &order= ' .$ new_order .'">Thread</a></td> '
1806- .'<td align="left" class="small hide-mobile" width="11%"><a href="?sortby=tu_username &order= ' .$ new_order .'">Thread starter</a></td> '
1807- .'<td align="center" class="hide-mobile"><a href="?sortby=ct.thread_id &order= ' .$ new_order .'">Datum</a></td> '
1808- .'<td align="center" class="small hide-mobile"><a href="?sortby=numposts &order= ' .$ new_order .'">#</a></td> '
1809- .'<td align="left" class="small" width="25%"><a href="?sortby=last_post_date &order= ' .$ new_order .'">Last comment</a></td> '
1825+ .'<td align="left" width="30%"><a href="?sortby=threadname &order= ' .$ new_order .'">Thread</a></td> '
1826+ .'<td align="left" class="small hide-mobile" width="11%"><a href="?sortby=threadstarter &order= ' .$ new_order .'">Thread starter</a></td> '
1827+ .'<td align="center" class="hide-mobile"><a href="?sortby=threadid &order= ' .$ new_order .'">Datum</a></td> '
1828+ .'<td align="center" class="small hide-mobile"><a href="?sortby=threadposts &order= ' .$ new_order .'">#</a></td> '
1829+ .'<td align="left" class="small" width="25%"><a href="?sortby=threadupdated &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