It's 'polls', not 'poll' (since Geeklog 1.4.0) and shouldn't really be referred to in non-plugin code
3 /* Reminder: always indent with 4 spaces (no tabs). */
4 // +---------------------------------------------------------------------------+
6 // +---------------------------------------------------------------------------+
9 // | Geeklog comment library. |
10 // +---------------------------------------------------------------------------+
11 // | Copyright (C) 2000-2009 by the following authors: |
13 // | Authors: Tony Bibbs - tony AT tonybibbs DOT com |
14 // | Mark Limburg - mlimburg AT users DOT sourceforge DOT net |
15 // | Jason Whittenburg - jwhitten AT securitygeeks DOT com |
16 // | Dirk Haun - dirk AT haun-online DOT de |
17 // | Vincent Furia - vinny01 AT users DOT sourceforge DOT net |
18 // | Jared Wenerd - wenerd87 AT gmail DOT com |
19 // +---------------------------------------------------------------------------+
21 // | This program is free software; you can redistribute it and/or |
22 // | modify it under the terms of the GNU General Public License |
23 // | as published by the Free Software Foundation; either version 2 |
24 // | of the License, or (at your option) any later version. |
26 // | This program is distributed in the hope that it will be useful, |
27 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
28 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
29 // | GNU General Public License for more details. |
31 // | You should have received a copy of the GNU General Public License |
32 // | along with this program; if not, write to the Free Software Foundation, |
33 // | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
35 // +---------------------------------------------------------------------------+
37 if (strpos(strtolower($_SERVER['PHP_SELF']), 'lib-comment.php') !== false) {
38 die('This file can not be used on its own!');
41 if ($_CONF['allow_user_photo']) {
43 * only needed for the USER_getPhoto function
45 require_once $_CONF['path_system'] . 'lib-user.php';
49 * This function displays the comment control bar
51 * Prints the control that allows the user to interact with Geeklog Comments
53 * @param string $sid ID of item in question
54 * @param string $title Title of item
55 * @param string $type Type of item (i.e. article, photo, etc)
56 * @param string $order Order that comments are displayed in
57 * @param string $mode Mode (nested, flat, etc.)
58 * @param int $ccode Comment code: -1=no comments, 0=allowed, 1=closed
59 * @return string HTML Formated comment bar
60 * @see CMT_userComments
63 function CMT_commentBar( $sid, $title, $type, $order, $mode, $ccode = 0 )
65 global $_CONF, $_TABLES, $_USER, $LANG01;
67 $parts = explode( '/', $_SERVER['PHP_SELF'] );
68 $page = array_pop( $parts );
69 $nrows = DB_count( $_TABLES['comments'], array( 'sid', 'type' ),
70 array( $sid, $type ));
72 $commentbar = new Template( $_CONF['path_layout'] . 'comment' );
73 $commentbar->set_file( array( 'commentbar' => 'commentbar.thtml' ));
74 $commentbar->set_var( 'xhtml', XHTML );
75 $commentbar->set_var( 'site_url', $_CONF['site_url'] );
76 $commentbar->set_var( 'site_admin_url', $_CONF['site_admin_url'] );
77 $commentbar->set_var( 'layout_url', $_CONF['layout_url'] );
79 $commentbar->set_var( 'lang_comments', $LANG01[3] );
80 $commentbar->set_var( 'lang_refresh', $LANG01[39] );
81 $commentbar->set_var( 'lang_reply', $LANG01[60] );
82 $commentbar->set_var( 'lang_disclaimer', $LANG01[26] );
85 $commentbar->set_var( 'reply_hidden_or_submit', 'submit' );
87 $commentbar->set_var( 'reply_hidden_or_submit', 'hidden' );
89 $commentbar->set_var( 'num_comments', COM_numberFormat( $nrows ));
90 $commentbar->set_var( 'comment_type', $type );
91 $commentbar->set_var( 'sid', $sid );
93 $cmt_title = stripslashes($title);
94 $commentbar->set_var('story_title', $cmt_title);
95 // Article's are pre-escaped.
96 if ($type != 'article') {
97 $cmt_title = htmlspecialchars($cmt_title);
99 $commentbar->set_var('comment_title', $cmt_title);
101 if ($type == 'article') {
102 $articleUrl = COM_buildUrl($_CONF['site_url']
103 . "/article.php?story=$sid");
104 } else { // for a plugin
106 * Link to plugin defined link or lacking that a generic link
107 * that the plugin should support (hopefully)
109 list($plgurl, $plgid) = PLG_getCommentUrlId($type);
110 $articleUrl = "$plgurl?$plgid=$sid";
113 $commentbar->set_var('article_url', $articleUrl);
114 if ($page == 'comment.php') {
115 $link = COM_createLink($cmt_title, $articleUrl,
116 array('class' => 'non-ul b'));
117 $commentbar->set_var('story_link', $link);
118 $commentbar->set_var('start_storylink_anchortag',
119 '<a href="' . $articleUrl . '" class="non-ul">');
120 $commentbar->set_var('end_storylink_anchortag', '</a>');
122 $commentbar->set_var('story_link', $articleUrl);
125 if( !empty( $_USER['uid'] ) && ( $_USER['uid'] > 1 )) {
126 $username = $_USER['username'];
127 $fullname = $_USER['fullname'];
129 $result = DB_query( "SELECT username,fullname FROM {$_TABLES['users']} WHERE uid = 1" );
130 $N = DB_fetchArray( $result );
131 $username = $N['username'];
132 $fullname = $N['fullname'];
134 if( empty( $fullname )) {
135 $fullname = $username;
137 $commentbar->set_var( 'user_name', $username );
138 $commentbar->set_var( 'user_fullname', $fullname );
140 if( !empty( $_USER['username'] )) {
141 $author = COM_getDisplayName( $_USER['uid'], $username, $fullname );
142 $commentbar->set_var( 'user_nullname', $author );
143 $commentbar->set_var( 'author', $author );
144 $commentbar->set_var( 'login_logout_url',
145 $_CONF['site_url'] . '/users.php?mode=logout' );
146 $commentbar->set_var( 'lang_login_logout', $LANG01[35] );
148 $commentbar->set_var( 'user_nullname', '' );
149 $commentbar->set_var( 'login_logout_url',
150 $_CONF['site_url'] . '/users.php?mode=new' );
151 $commentbar->set_var( 'lang_login_logout', $LANG01[61] );
154 if( $page == 'comment.php' ) {
155 $commentbar->set_var( 'parent_url',
156 $_CONF['site_url'] . '/comment.php' );
158 if( $_REQUEST['mode'] == 'view' ) {
159 $hidden .= '<input type="hidden" name="cid" value="' . $_REQUEST['cid'] . '"' . XHTML . '>';
160 $hidden .= '<input type="hidden" name="pid" value="' . $_REQUEST['cid'] . '"' . XHTML . '>';
162 else if( $_REQUEST['mode'] == 'display' ) {
163 $hidden .= '<input type="hidden" name="pid" value="' . $_REQUEST['pid'] . '"' . XHTML . '>';
165 $commentbar->set_var( 'hidden_field', $hidden .
166 '<input type="hidden" name="mode" value="' . $_REQUEST['mode'] . '"' . XHTML . '>' );
167 } else if( $type == 'article' ) {
168 $commentbar->set_var( 'parent_url',
169 $_CONF['site_url'] . '/article.php' );
170 $commentbar->set_var( 'hidden_field',
171 '<input type="hidden" name="story" value="' . $sid . '"' . XHTML . '>' );
173 // Link to plugin defined link or lacking that a generic link that the plugin should support (hopefully)
174 list($plgurl, $plgid) = PLG_getCommentUrlId($type);
175 $commentbar->set_var( 'parent_url', $plgurl );
176 $commentbar->set_var( 'hidden_field',
177 '<input type="hidden" name="' . $plgid . '" value="' . $sid . '"' . XHTML . '>' );
181 $selector = '<select name="order">' . LB
182 . COM_optionList( $_TABLES['sortcodes'], 'code,name', $order )
184 $commentbar->set_var( 'order_selector', $selector);
187 if( $page == 'comment.php' ) {
188 $selector = '<select name="format">';
190 $selector = '<select name="mode">';
193 . COM_optionList( $_TABLES['commentmodes'], 'mode,name', $mode )
195 $commentbar->set_var( 'mode_selector', $selector);
197 return $commentbar->finish( $commentbar->parse( 'output', 'commentbar' ));
202 * This function prints &$comments (db results set of comments) in comment format
203 * -For previews, &$comments is assumed to be an associative array containing
204 * data for a single comment.
206 * @param array &$comments Database result set of comments to be printed
207 * @param string $mode 'flat', 'threaded', etc
208 * @param string $type Type of item (article, polls, etc.)
209 * @param string $order How to order the comments 'ASC' or 'DESC'
210 * @param boolean $delete_option if current user can delete comments
211 * @param boolean $preview Preview display (for edit) or not
212 * @param int $ccode Comment code: -1=no comments, 0=allowed, 1=closed
213 * @return string HTML Formated Comment
216 function CMT_getComment( &$comments, $mode, $type, $order, $delete_option = false, $preview = false, $ccode = 0 )
218 global $_CONF, $_TABLES, $_USER, $LANG01, $LANG03, $MESSAGE, $_IMAGE_TYPE;
220 $indent = 0; // begin with 0 indent
221 $retval = ''; // initialize return value
223 $template = new Template( $_CONF['path_layout'] . 'comment' );
224 $template->set_file( array( 'comment' => 'comment.thtml',
225 'thread' => 'thread.thtml' ));
227 // generic template variables
228 $template->set_var( 'xhtml', XHTML );
229 $template->set_var( 'site_url', $_CONF['site_url'] );
230 $template->set_var( 'site_admin_url', $_CONF['site_admin_url'] );
231 $template->set_var( 'layout_url', $_CONF['layout_url'] );
232 $template->set_var( 'lang_authoredby', $LANG01[42] );
233 $template->set_var( 'lang_on', $LANG01[36] );
234 $template->set_var( 'lang_permlink', $LANG01[120] );
235 $template->set_var( 'order', $order );
238 $template->set_var( 'lang_replytothis', $LANG01[43] );
239 $template->set_var( 'lang_reply', $LANG01[25] );
241 $template->set_var( 'lang_replytothis', '' );
242 $template->set_var( 'lang_reply', '' );
245 // Make sure we have a default value for comment indentation
246 if (!isset($_CONF['comment_indent'])) {
247 $_CONF['comment_indent'] = 25;
252 if (empty( $A['nice_date'])) {
253 $A['nice_date'] = time();
255 if (!isset($A['cid'])) {
258 if (!isset($A['photo'])) {
259 if (isset($_USER['photo'])) {
260 $A['photo'] = $_USER['photo'];
265 if (! isset($A['email'])) {
266 if (isset($_USER['email'])) {
267 $A['email'] = $_USER['email'];
274 $A = DB_fetchArray( $comments );
282 if ($delete_option && !$preview) {
283 $token = SEC_createToken();
286 // check for comment edit
290 // check for comment edit
291 $commentedit = DB_query("SELECT cid,uid,UNIX_TIMESTAMP(time) AS time FROM {$_TABLES['commentedits']} WHERE cid = {$A['cid']}");
292 $B = DB_fetchArray($commentedit);
293 if ($B) { //comment edit present
294 // get correct editor name
295 if ($A['uid'] == $B['uid']) {
296 $editname = $A['username'];
298 $editname = DB_getItem($_TABLES['users'], 'username',
301 // add edit info to text
302 $A['comment'] .= '<div class="comment-edit">' . $LANG03[30] . ' '
303 . strftime($_CONF['date'], $B['time']) . ' '
304 . $LANG03[31] . ' ' . $editname
305 . '</div><!-- /COMMENTEDIT -->';
308 // determines indentation for current comment
309 if ($mode == 'threaded' || $mode == 'nested') {
310 $indent = ($A['indent'] - $A['pindent']) * $_CONF['comment_indent'];
314 $template->set_var('indent', $indent);
315 $template->set_var('author_name', strip_tags($A['username']));
316 $template->set_var('author_id', $A['uid']);
317 $template->set_var('cid', $A['cid']);
318 $template->set_var('cssid', $row % 2);
322 if (! empty($A['fullname'])) {
323 $fullname = $A['fullname'];
325 $fullname = COM_getDisplayName($A['uid'], $A['username'],
327 $template->set_var('author_fullname', $fullname);
328 $template->set_var('author', $fullname);
329 $alttext = $fullname;
332 if ($_CONF['allow_user_photo']) {
333 if (isset ($A['photo']) && empty($A['photo'])) {
334 $A['photo'] = '(none)';
336 $photo = USER_getPhoto($A['uid'], $A['photo'], $A['email']);
338 if( !empty( $photo )) {
339 $template->set_var( 'author_photo', $photo );
340 $camera_icon = '<img src="' . $_CONF['layout_url']
341 . '/images/smallcamera.' . $_IMAGE_TYPE . '" alt=""' . XHTML . '>';
342 $template->set_var( 'camera_icon',
345 $_CONF['site_url'] . '/users.php?mode=profile&uid=' . $A['uid']
349 $template->set_var( 'author_photo', '' );
350 $template->set_var( 'camera_icon', '' );
353 $template->set_var( 'start_author_anchortag', '<a href="'
354 . $_CONF['site_url'] . '/users.php?mode=profile&uid='
355 . $A['uid'] . '">' );
356 $template->set_var( 'end_author_anchortag', '</a>' );
357 $template->set_var( 'author_link',
360 $_CONF['site_url'] . '/users.php?mode=profile&uid=' . $A['uid']
365 //comment is from anonymous user
366 if (isset($A['name'])) {
367 $A['username'] = strip_tags($A['name']);
369 $template->set_var( 'author', $A['username'] );
370 $template->set_var( 'author_fullname', $A['username'] );
371 $template->set_var( 'author_link', $A['username'] );
372 $template->set_var( 'author_photo', '' );
373 $template->set_var( 'camera_icon', '' );
374 $template->set_var( 'start_author_anchortag', '' );
375 $template->set_var( 'end_author_anchortag', '' );
378 // hide reply link from anonymous users if they can't post replies
379 $hidefromanon = false;
380 if( empty( $_USER['username'] ) && (( $_CONF['loginrequired'] == 1 )
381 || ( $_CONF['commentsloginrequired'] == 1 ))) {
382 $hidefromanon = true;
385 // this will hide HTML that should not be viewed in preview mode
386 if( $preview || $hidefromanon ) {
387 $template->set_var( 'hide_if_preview', 'style="display:none"' );
389 $template->set_var( 'hide_if_preview', '' );
392 // for threaded mode, add a link to comment parent
393 if( $mode == 'threaded' && $A['pid'] != 0 && $indent == 0 ) {
394 $result = DB_query( "SELECT title,pid FROM {$_TABLES['comments']} WHERE cid = '{$A['pid']}'" );
395 $P = DB_fetchArray( $result );
396 if( $P['pid'] != 0 ) {
397 $plink = $_CONF['site_url'] . '/comment.php?mode=display&sid='
398 . $A['sid'] . '&title=' . urlencode( htmlspecialchars( $P['title'] ))
399 . '&type=' . $type . '&order=' . $order . '&pid='
400 . $P['pid'] . '&format=threaded';
402 $plink = $_CONF['site_url'] . '/comment.php?mode=view&sid='
403 . $A['sid'] . '&title=' . urlencode( htmlspecialchars( $P['title'] ))
404 . '&type=' . $type . '&order=' . $order . '&cid='
405 . $A['pid'] . '&format=threaded';
407 $parent_link = COM_createLink($LANG01[44], $plink) . ' | ';
408 $template->set_var('parent_link', $parent_link);
410 $template->set_var('parent_link', '');
413 $template->set_var( 'date', strftime( $_CONF['date'], $A['nice_date'] ));
414 $template->set_var( 'sid', $A['sid'] );
415 $template->set_var( 'type', $A['type'] );
417 // COMMENT edit rights
418 $edit_option = false;
419 if (isset($A['uid']) && isset($_USER['uid'])
420 && ($_USER['uid'] == $A['uid']) && ($_CONF['comment_edit'] == 1)
421 && ((time() - $A['nice_date']) < $_CONF['comment_edittime'])
422 && (DB_getItem($_TABLES['comments'], 'COUNT(*)',
423 "pid = {$A['cid']}") == 0)) {
426 $token = SEC_createToken();
428 } elseif (SEC_hasRights('comment.moderate')) {
435 $editlink = $_CONF['site_url'] . '/comment.php?mode=edit&cid='
436 . $A['cid'] . '&sid=' . $A['sid'] . '&type=' . $type;
437 $edit = COM_createLink($LANG01[4], $editlink) . ' | ';
442 if (($_CONF['allow_reply_notifications'] == 1) && !COM_isAnonUser()
443 && isset($A['uid']) && isset($_USER['uid'])
444 && ($_USER['uid'] == $A['uid'])) {
445 $hash = DB_getItem($_TABLES['commentnotifications'], 'deletehash',
446 "cid = {$A['cid']} AND uid = {$_USER['uid']}");
447 if (! empty($hash)) {
448 $unsublink = $_CONF['site_url']
449 . '/comment.php?mode=unsubscribe&key=' . $hash;
450 $unsubattr = array('title' => $LANG03[43]);
451 $unsubscribe = COM_createLink($LANG03[42], $unsublink,
456 // if deletion is allowed, displays delete link
457 if ($delete_option) {
460 // always place edit option first, if available
461 if (! empty($edit)) {
465 // actual delete option
466 $dellink = $_CONF['site_url'] . '/comment.php?mode=delete&cid='
467 . $A['cid'] . '&sid=' . $A['sid'] . '&type=' . $type
468 . '&' . CSRF_TOKEN . '=' . $token;
469 $delattr = array('onclick' => "return confirm('{$MESSAGE[76]}');");
470 $deloption .= COM_createLink($LANG01[28], $dellink, $delattr) . ' | ';
472 if (!empty($A['ipaddress'])) {
473 if (empty($_CONF['ip_lookup'])) {
474 $deloption .= $A['ipaddress'] . ' | ';
476 $iplookup = str_replace('*', $A['ipaddress'],
477 $_CONF['ip_lookup']);
478 $deloption .= COM_createLink($A['ipaddress'], $iplookup) . ' | ';
482 if (! empty($unsubscribe)) {
483 $deloption .= $unsubscribe;
486 $template->set_var('delete_option', $deloption);
487 } elseif ($edit_option) {
488 $template->set_var('delete_option', $edit . $unsubscribe);
489 } elseif (! COM_isAnonUser()) {
491 if ($A['uid'] != $_USER['uid']) {
492 $reportthis_link = $_CONF['site_url']
493 . '/comment.php?mode=report&cid=' . $A['cid']
494 . '&type=' . $type;
495 $report_attr = array('title' => $LANG01[110]);
496 $reportthis = COM_createLink($LANG01[109], $reportthis_link,
497 $report_attr) . ' | ';
499 $template->set_var('delete_option', $reportthis . $unsubscribe);
501 $template->set_var('delete_option', '');
504 //and finally: format the actual text of the comment, but check only the text, not sig or edit
505 $text = str_replace('<!-- COMMENTSIG --><div class="comment-sig">', '',
507 $text = str_replace('</div><!-- /COMMENTSIG -->', '', $text);
508 $text = str_replace('<div class="comment-edit">', '', $text);
509 $text = str_replace('</div><!-- /COMMENTEDIT -->', '', $text);
510 if( preg_match( '/<.*>/', $text ) == 0 ) {
511 $A['comment'] = nl2br( $A['comment'] );
514 // highlight search terms if specified
515 if( !empty( $_REQUEST['query'] )) {
516 $A['comment'] = COM_highlightQuery( $A['comment'],
517 $_REQUEST['query'] );
520 $A['comment'] = str_replace( '$', '$', $A['comment'] );
521 $A['comment'] = str_replace( '{', '{', $A['comment'] );
522 $A['comment'] = str_replace( '}', '}', $A['comment'] );
524 // Replace any plugin autolink tags
525 $A['comment'] = PLG_replaceTags( $A['comment'] );
527 // create a reply to link
530 $reply_link = $_CONF['site_url'] . '/comment.php?sid=' . $A['sid']
531 . '&pid=' . $A['cid'] . '&title='
532 . urlencode($A['title']) . '&type=' . $A['type'];
533 $reply_option = COM_createLink($LANG01[43], $reply_link,
534 array('rel' => 'nofollow')) . ' | ';
535 $template->set_var('reply_option', $reply_option);
537 $template->set_var('reply_option', '');
539 $template->set_var('reply_link', $reply_link);
541 // format title for display, must happen after reply_link is created
542 $A['title'] = htmlspecialchars( $A['title'] );
543 $A['title'] = str_replace( '$', '$', $A['title'] );
545 $template->set_var( 'title', $A['title'] );
546 $template->set_var( 'comments', $A['comment'] );
548 // parse the templates
549 if( ($mode == 'threaded') && $indent > 0 ) {
550 $template->set_var( 'pid', $A['pid'] );
551 $retval .= $template->parse( 'output', 'thread' );
553 $template->set_var( 'pid', $A['cid'] );
554 $retval .= $template->parse( 'output', 'comment' );
557 } while( $A = DB_fetchArray( $comments ));
563 * This function displays the comments in a high level format.
565 * Begins displaying user comments for an item
567 * @param string $sid ID for item to show comments for
568 * @param string $title Title of item
569 * @param string $type Type of item (article, polls, etc.)
570 * @param string $order How to order the comments 'ASC' or 'DESC'
571 * @param string $mode comment mode (nested, flat, etc.)
572 * @param int $pid id of parent comment
573 * @param int $page page number of comments to display
574 * @param boolean $cid true if $pid should be interpreted as a cid instead
575 * @param boolean $delete_option if current user can delete comments
576 * @param int $ccode Comment code: -1=no comments, 0=allowed, 1=closed
577 * @return string HTML Formated Comments
578 * @see CMT_commentBar
581 function CMT_userComments( $sid, $title, $type='article', $order='', $mode='', $pid = 0, $page = 1, $cid = false, $delete_option = false, $ccode = 0 )
583 global $_CONF, $_TABLES, $_USER, $LANG01;
585 if( !empty( $_USER['uid'] ) ) {
586 $result = DB_query( "SELECT commentorder,commentmode,commentlimit FROM {$_TABLES['usercomment']} WHERE uid = '{$_USER['uid']}'" );
587 $U = DB_fetchArray( $result );
588 if( empty( $order ) ) {
589 $order = $U['commentorder'];
591 if( empty( $mode ) ) {
592 $mode = $U['commentmode'];
594 $limit = $U['commentlimit'];
597 if( $order != 'ASC' && $order != 'DESC' ) {
601 if( empty( $mode )) {
602 $mode = $_CONF['comment_mode'];
605 if( empty( $limit )) {
606 $limit = $_CONF['comment_limit'];
609 if( !is_numeric($page) || $page < 1 ) {
613 $start = $limit * ( $page - 1 );
615 $template = new Template( $_CONF['path_layout'] . 'comment' );
616 $template->set_file( array( 'commentarea' => 'startcomment.thtml' ));
617 $template->set_var( 'xhtml', XHTML );
618 $template->set_var( 'site_url', $_CONF['site_url'] );
619 $template->set_var( 'site_admin_url', $_CONF['site_admin_url'] );
620 $template->set_var( 'layout_url', $_CONF['layout_url'] );
621 $template->set_var( 'commentbar',
622 CMT_commentBar( $sid, $title, $type, $order, $mode, $ccode ));
623 $template->set_var( 'sid', $sid );
624 $template->set_var( 'comment_type', $type );
626 if( $mode == 'nested' || $mode == 'threaded' || $mode == 'flat' ) {
633 $q = "SELECT c.*, u.username, u.fullname, u.photo, u.email, "
634 . "UNIX_TIMESTAMP(c.date) AS nice_date "
635 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['users']} AS u "
636 . "WHERE c.uid = u.uid AND c.cid = $pid AND type='{$type}'";
638 $count = DB_count( $_TABLES['comments'],
639 array( 'sid', 'type' ), array( $sid, $type ));
641 $q = "SELECT c.*, u.username, u.fullname, u.photo, u.email, "
642 . "UNIX_TIMESTAMP(c.date) AS nice_date "
643 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['users']} AS u "
644 . "WHERE c.uid = u.uid AND c.sid = '$sid' AND type='{$type}' "
645 . "ORDER BY date $order LIMIT $start, $limit";
652 if( $order == 'DESC' ) {
653 $cOrder = 'c.rht DESC';
655 $cOrder = 'c.lft ASC';
658 // We can simplify the query, and hence increase performance
659 // when pid = 0 (when fetching all the comments for a given sid)
660 if( $cid ) { // pid refers to commentid rather than parentid
661 // count the total number of applicable comments
662 $q2 = "SELECT COUNT(*) "
663 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['comments']} AS c2 "
664 . "WHERE c.sid = '$sid' AND (c.lft >= c2.lft AND c.lft <= c2.rht) "
665 . "AND c2.cid = $pid AND c.type='{$type}'";
666 $result = DB_query( $q2 );
667 list( $count ) = DB_fetchArray( $result );
669 $q = "SELECT c.*, u.username, u.fullname, u.photo, u.email, c2.indent AS pindent, "
670 . "UNIX_TIMESTAMP(c.date) AS nice_date "
671 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['comments']} AS c2, "
672 . "{$_TABLES['users']} AS u "
673 . "WHERE c.sid = '$sid' AND (c.lft >= c2.lft AND c.lft <= c2.rht) "
674 . "AND c2.cid = $pid AND c.uid = u.uid AND c.type='{$type}' "
675 . "ORDER BY $cOrder LIMIT $start, $limit";
676 } else { // pid refers to parentid rather than commentid
677 if( $pid == 0 ) { // the simple, fast case
678 // count the total number of applicable comments
679 $count = DB_count( $_TABLES['comments'],
680 array( 'sid', 'type' ), array( $sid, $type ));
682 $q = "SELECT c.*, u.username, u.fullname, u.photo, u.email, 0 AS pindent, "
683 . "UNIX_TIMESTAMP(c.date) AS nice_date "
684 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['users']} AS u "
685 . "WHERE c.sid = '$sid' AND c.uid = u.uid AND type='{$type}' "
686 . "ORDER BY $cOrder LIMIT $start, $limit";
688 // count the total number of applicable comments
689 $q2 = "SELECT COUNT(*) "
690 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['comments']} AS c2 "
691 . "WHERE c.sid = '$sid' AND (c.lft > c2.lft AND c.lft < c2.rht) "
692 . "AND c2.cid = $pid AND c.type='{$type}'";
693 $result = DB_query($q2);
694 list($count) = DB_fetchArray($result);
696 $q = "SELECT c.*, u.username, u.fullname, u.photo, u.email, c2.indent + 1 AS pindent, "
697 . "UNIX_TIMESTAMP(c.date) AS nice_date "
698 . "FROM {$_TABLES['comments']} AS c, {$_TABLES['comments']} AS c2, "
699 . "{$_TABLES['users']} AS u "
700 . "WHERE c.sid = '$sid' AND (c.lft > c2.lft AND c.lft < c2.rht) "
701 . "AND c2.cid = $pid AND c.uid = u.uid AND c.type='{$type}' "
702 . "ORDER BY $cOrder LIMIT $start, $limit";
709 $result = DB_query( $q );
710 $thecomments .= CMT_getComment( $result, $mode, $type, $order,
711 $delete_option, false, $ccode );
714 $tot_pages = ceil($count / $limit);
715 $pLink = $_CONF['site_url'] . "/article.php?story=$sid&type=$type&order=$order&mode=$mode";
716 $template->set_var('pagenav',
717 COM_printPageNavigation($pLink, $page, $tot_pages));
719 $template->set_var('comments', $thecomments);
720 $retval = $template->finish($template->parse('output', 'commentarea'));
727 * Displays the comment form
729 * @param string $title Title of comment
730 * @param string $comment Text of comment
731 * @param string $sid ID of object comment belongs to
732 * @param int $pid ID of parent comment
733 * @param string $type Type of object comment is posted to
734 * @param string $mode Mode, e.g. 'preview'
735 * @param string $postmode Indicates if comment is plain text or HTML
736 * @return string HTML for comment form
739 function CMT_commentForm($title,$comment,$sid,$pid='0',$type,$mode,$postmode)
741 global $_CONF, $_TABLES, $_USER, $LANG03, $LANG12, $LANG_LOGIN,
746 // never trust $uid ...
747 if (empty ($_USER['uid'])) {
750 $uid = $_USER['uid'];
754 $table = $_TABLES['comments'];
755 if (($mode == 'edit' || $mode == $LANG03[28]) && isset($_REQUEST['cid'])) {
756 $cid = COM_applyFilter ($_REQUEST['cid']);
757 $commentuid = DB_getItem ($_TABLES['comments'], 'uid', "cid = '$cid'");
758 } elseif ($mode == 'editsubmission' || $mode == $LANG03[34]) {
759 $cid = COM_applyFilter ($_REQUEST['cid']);
760 $commentuid = DB_getItem ($_TABLES['commentsubmissions'], 'uid', "cid = '$cid'");
761 $table = $_TABLES['commentsubmissions'];
764 if (COM_isAnonUser() &&
765 (($_CONF['loginrequired'] == 1) || ($_CONF['commentsloginrequired'] == 1))) {
766 $retval .= COM_startBlock ($LANG_LOGIN[1], '',
767 COM_getBlockTemplate ('_msg_block', 'header'));
768 $loginreq = new Template($_CONF['path_layout'] . 'submit');
769 $loginreq->set_file('loginreq', 'submitloginrequired.thtml');
770 $loginreq->set_var( 'xhtml', XHTML );
771 $loginreq->set_var('login_message', $LANG_LOGIN[2]);
772 $loginreq->set_var('site_url', $_CONF['site_url']);
773 $loginreq->set_var('site_admin_url', $_CONF['site_admin_url']);
774 $loginreq->set_var('lang_login', $LANG_LOGIN[3]);
775 $loginreq->set_var('lang_newuser', $LANG_LOGIN[4]);
776 $loginreq->parse('errormsg', 'loginreq');
777 $retval .= $loginreq->finish($loginreq->get_var('errormsg'));
778 $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
781 COM_clearSpeedlimit ($_CONF['commentspeedlimit'], 'comment');
784 if ($mode != 'edit' && $mode != 'editsubmission'
785 && $mode != $LANG03[28] && $mode != $LANG03[34]) {
786 // not edit mode or preview changes
787 $last = COM_checkSpeedlimit ('comment');
791 $retval .= COM_startBlock ($LANG12[26], '',
792 COM_getBlockTemplate ('_msg_block', 'header'))
796 . COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
799 if (($_CONF['advanced_editor'] == 1) && file_exists ($_CONF['path_layout'] . 'comment/commentform_advanced.thtml')) {
801 } elseif (empty ($postmode)) {
802 $postmode = $_CONF['postmode'];
806 // $comment / $newcomment is what goes into the preview / is
807 // actually stored in the database -> strip HTML
808 // $commenttext is what the user entered and goes back into the
809 // <textarea> -> don't strip HTML
811 $commenttext = htmlspecialchars (COM_stripslashes ($comment));
813 // Replace $, {, and } with special HTML equivalents
814 $commenttext = str_replace('$','$',$commenttext);
815 $commenttext = str_replace('{','{',$commenttext);
816 $commenttext = str_replace('}','}',$commenttext);
818 $title = COM_checkWords (strip_tags (COM_stripslashes ($title)));
819 // $title = str_replace('$','$',$title); done in CMT_getComment
821 $_POST['title'] = $title;
822 $newcomment = $comment;
823 if ($mode == $LANG03[28] ) { // for preview
824 $newcomment = CMT_prepareText($comment, $postmode, $type, true, $cid);
825 } elseif ($mode == $LANG03[34]) {
826 $newcomment = CMT_prepareText($comment, $postmode, $type, true);
828 $newcomment = CMT_prepareText($comment, $postmode, $type);
830 $_POST['comment'] = $newcomment;
833 if (($mode == $LANG03[14] || $mode == $LANG03[28] || $mode == $LANG03[34]) && !empty($title) && !empty($comment) ) {
834 $start = new Template( $_CONF['path_layout'] . 'comment' );
835 $start->set_file( array( 'comment' => 'startcomment.thtml' ));
836 $start->set_var( 'xhtml', XHTML );
837 $start->set_var( 'site_url', $_CONF['site_url'] );
838 $start->set_var( 'site_admin_url', $_CONF['site_admin_url'] );
839 $start->set_var( 'layout_url', $_CONF['layout_url'] );
840 $start->set_var( 'hide_if_preview', 'style="display:none"' );
842 // Clean up all the vars
844 foreach ($_POST as $key => $value) {
845 if (($key == 'pid') || ($key == 'cid')) {
846 $A[$key] = COM_applyFilter ($_POST[$key], true);
847 } else if (($key == 'title') || ($key == 'comment')) {
848 // these have already been filtered above
849 $A[$key] = $_POST[$key];
850 } else if ($key == 'username') {
851 $A[$key] = htmlspecialchars(COM_checkWords(strip_tags(
852 COM_stripslashes($_POST[$key]))));
854 $A[$key] = COM_applyFilter ($_POST[$key]);
858 // correct time and username for edit preview
859 if (($mode == $LANG03[28]) || ($mode == $LANG03[34])) {
860 $A['nice_date'] = DB_getItem($table, 'UNIX_TIMESTAMP(date)',
862 if ($_USER['uid'] != $commentuid) {
863 $uresult = DB_query("SELECT username, fullname, email, photo FROM {$_TABLES['users']} WHERE uid = $commentuid");
864 $A = array_merge($A, DB_fetchArray($uresult));
867 if (empty ($A['username'])) {
868 $A['username'] = DB_getItem ($_TABLES['users'], 'username',
871 $thecomments = CMT_getComment ($A, 'flat', $type, 'ASC', false,
874 $start->set_var( 'comments', $thecomments );
875 $retval .= COM_startBlock ($LANG03[14])
876 . $start->finish( $start->parse( 'output', 'comment' ))
878 } else if ($mode == $LANG03[14]) {
879 $retval .= COM_startBlock ($LANG03[17], '',
880 COM_getBlockTemplate ('_msg_block', 'header'))
882 . COM_endBlock(COM_getBlockTemplate ('_msg_block', 'footer'));
886 $comment_template = new Template($_CONF['path_layout'] . 'comment');
887 if (($_CONF['advanced_editor'] == 1) && file_exists ($_CONF['path_layout'] . 'comment/commentform_advanced.thtml')) {
888 $comment_template->set_file('form','commentform_advanced.thtml');
890 $comment_template->set_file('form','commentform.thtml');
892 $comment_template->set_var('xhtml', XHTML);
893 $comment_template->set_var('site_url', $_CONF['site_url']);
894 $comment_template->set_var('site_admin_url', $_CONF['site_admin_url']);
895 $comment_template->set_var('layout_url', $_CONF['layout_url']);
896 $comment_template->set_var('start_block_postacomment', COM_startBlock($LANG03[1]));
897 if ($_CONF['show_fullname'] == 1) {
898 $comment_template->set_var('lang_username', $LANG_ACCESS['name']);
900 $comment_template->set_var('lang_username', $LANG03[5]);
902 $comment_template->set_var('sid', $sid);
903 $comment_template->set_var('pid', $pid);
904 $comment_template->set_var('type', $type);
906 $formurl = $_CONF['site_url'] . '/comment.php';
907 if ($mode == 'edit' || $mode == $LANG03[28]) { //edit modes
908 $comment_template->set_var('start_block_postacomment',
909 COM_startBlock($LANG03[32]));
910 $comment_template->set_var('cid', '<input type="hidden" name="cid" value="' . $cid . '"' . XHTML . '>');
911 } else if ($mode == 'editsubmission' || $mode == $LANG03[34]) {
912 $comment_template->set_var('start_block_postacomment',
913 COM_startBlock($LANG03[33]));
914 $comment_template->set_var('cid', '<input type="hidden" name="cid" value="' . $cid . '"' . XHTML . '>');
916 $comment_template->set_var('start_block_postacomment',
917 COM_startBlock($LANG03[1]));
918 $comment_template->set_var('cid', '');
920 $comment_template->set_var('form_url', $formurl);
922 if (COM_isAnonUser()) {
924 $comment_template->set_var('uid', 1);
925 if (isset($A['username'])) {
926 $name = $A['username']; // for preview
927 } elseif (isset($_COOKIE[$_CONF['cookie_anon_name']])) {
928 // stored as cookie, name used before
929 $name = htmlspecialchars(COM_checkWords(strip_tags(
930 COM_stripslashes($_COOKIE[$_CONF['cookie_anon_name']]))));
932 $name = COM_getDisplayName(1); // anonymous user
934 $usernameblock = '<input type="text" name="username" size="16" value="' .
935 $name . '" maxlength="32"' . XHTML . '>';
936 $comment_template->set_var('username', $usernameblock);
938 $comment_template->set_var('action_url',
939 $_CONF['site_url'] . '/users.php?mode=new');
940 $comment_template->set_var('lang_logoutorcreateaccount',
943 if ($commentuid != $_USER['uid']) {
944 $uresult = DB_query("SELECT username, fullname FROM {$_TABLES['users']} WHERE uid = $commentuid");
945 list($username, $fullname) = DB_fetchArray($uresult);
947 $username = $_USER['username'];
948 $fullname = $_USER['fullname'];
950 $comment_template->set_var('gltoken_name', CSRF_TOKEN);
951 $comment_template->set_var('gltoken', SEC_createToken());
952 $comment_template->set_var('uid', $commentuid);
953 $name = COM_getDisplayName($commentuid, $username, $fullname);
954 $comment_template->set_var('username', $name);
955 $comment_template->set_var('action_url',
956 $_CONF['site_url'] . '/users.php?mode=logout');
957 $comment_template->set_var('lang_logoutorcreateaccount',
961 if ($postmode == 'html') {
962 $comment_template->set_var ('show_texteditor', 'none');
963 $comment_template->set_var ('show_htmleditor', '');
965 $comment_template->set_var ('show_texteditor', '');
966 $comment_template->set_var ('show_htmleditor', 'none');
969 $comment_template->set_var('lang_title', $LANG03[16]);
970 $comment_template->set_var('title', htmlspecialchars($title));
971 $comment_template->set_var('lang_comment', $LANG03[9]);
972 $comment_template->set_var('comment', $commenttext);
973 $comment_template->set_var('lang_postmode', $LANG03[2]);
974 $comment_template->set_var('postmode_options',
975 COM_optionList($_TABLES['postmodes'], 'code,name', $postmode));
976 $comment_template->set_var('allowed_html',
977 COM_allowedHTML($type == 'article'
978 ? 'story.edit' : "$type.edit"));
979 $comment_template->set_var('lang_importantstuff', $LANG03[18]);
980 $comment_template->set_var('lang_instr_line1', $LANG03[19]);
981 $comment_template->set_var('lang_instr_line2', $LANG03[20]);
982 $comment_template->set_var('lang_instr_line3', $LANG03[21]);
983 $comment_template->set_var('lang_instr_line4', $LANG03[22]);
984 $comment_template->set_var('lang_instr_line5', $LANG03[23]);
986 if ($mode == 'edit' || $mode == $LANG03[28]) {
987 //editing comment or preview changes
988 $comment_template->set_var('lang_preview', $LANG03[28]);
989 } elseif ($mode == 'editsubmission' || $mode == $LANG03[34]) {
990 $comment_template->set_var('lang_preview', $LANG03[34]);
993 $comment_template->set_var('lang_preview', $LANG03[14]);
996 PLG_templateSetVars('comment', $comment_template);
997 if ($mode == $LANG03[28] || ($mode == 'edit' && $_CONF['skip_preview'] == 1)) {
999 $comment_template->set_var('save_option',
1000 '<input type="submit" name="mode" value="' . $LANG03[29]
1001 . '"' . XHTML . '>');
1002 } elseif ($mode == $LANG03[34] || ($mode == 'editsubmission' && $_CONF['skip_preview'] == 1)) {
1003 // editing submission comment
1004 $comment_template->set_var('save_option',
1005 '<input type="submit" name="mode" value="' . $LANG03[35]
1006 . '"' . XHTML . '>');
1007 } elseif (($_CONF['skip_preview'] == 1) || ($mode == $LANG03[14])) {
1008 $comment_template->set_var('save_option',
1009 '<input type="submit" name="mode" value="' . $LANG03[11]
1010 . '"' . XHTML . '>');
1014 if (($_CONF['allow_reply_notifications'] == 1 && $uid != 1) &&
1015 ($mode == '' || $mode == $LANG03[14] || $mode == 'error')) {
1017 if (isset($_POST['notify'])) {
1018 $checked = ' checked="checked"';
1020 $comment_template->set_var('notification',
1021 '<p><input type="checkbox"' . ' name="notify"' . $checked
1022 . '>' . $LANG03[36] . '</p>');
1025 $comment_template->set_var('end_block', COM_endBlock());
1026 $comment_template->parse('output', 'form');
1027 $retval .= $comment_template->finish($comment_template->get_var('output'));
1037 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
1038 * @param string $title Title of comment
1039 * @param string $comment Text of comment
1040 * @param string $sid ID of object receiving comment
1041 * @param int $pid ID of parent comment
1042 * @param string $type Type of comment this is (article, polls, etc)
1043 * @param string $postmode Indicates if text is HTML or plain text
1044 * @return int -1 == queued, 0 == comment saved, > 0 indicates error
1047 function CMT_saveComment($title, $comment, $sid, $pid, $type, $postmode)
1049 global $_CONF, $_TABLES, $_USER, $LANG03;
1054 if (empty ($_USER['uid'])) {
1057 $uid = $_USER['uid'];
1061 if (empty ($sid) || empty ($title) || empty ($comment) || empty ($type) ) {
1062 COM_errorLog("CMT_saveComment: $uid from {$_SERVER['REMOTE_ADDR']} tried "
1063 . 'to submit a comment with one or more missing values.');
1067 // Check that anonymous comments are allowed
1068 if (($uid == 1) && (($_CONF['loginrequired'] == 1)
1069 || ($_CONF['commentsloginrequired'] == 1))) {
1070 COM_errorLog("CMT_saveComment: IP address {$_SERVER['REMOTE_ADDR']} "
1071 . 'attempted to save a comment with anonymous comments disabled for site.');
1075 // Check for people breaking the speed limit
1076 COM_clearSpeedlimit ($_CONF['commentspeedlimit'], 'comment');
1077 $last = COM_checkSpeedlimit ('comment');
1079 COM_errorLog("CMT_saveComment: $uid from {$_SERVER['REMOTE_ADDR']} tried "
1080 . 'to submit a comment before the speed limit expired');
1084 // Let plugins have a chance to check for spam
1085 $spamcheck = '<h1>' . $title . '</h1><p>' . $comment . '</p>';
1086 $result = PLG_checkforSpam ($spamcheck, $_CONF['spamx']);
1087 // Now check the result and display message if spam action was taken
1089 // update speed limit nonetheless
1090 COM_updateSpeedlimit ('comment');
1092 // then tell them to get lost ...
1093 COM_displayMessageAndAbort ($result, 'spamx', 403, 'Forbidden');
1096 // Let plugins have a chance to decide what to do before saving the comment, return errors.
1097 if ($someError = PLG_commentPreSave($uid, $title, $comment, $sid, $pid, $type, $postmode)) {
1101 $comment = addslashes(CMT_prepareText($comment, $postmode, $type));
1102 $title = addslashes(COM_checkWords(strip_tags($title)));
1103 if (($uid == 1) && isset($_POST['username'])) {
1104 $anon = COM_getDisplayName(1);
1105 if (strcmp($_POST['username'], $anon) != 0) {
1106 $username = COM_checkWords(strip_tags(COM_stripslashes($_POST['username'])));
1107 setcookie($_CONF['cookie_anon_name'], $username, time() + 31536000,
1108 $_CONF['cookie_path'], $_CONF['cookiedomain'],
1109 $_CONF['cookiesecure']);
1110 $name = addslashes($username);
1114 // check for non-int pid's
1115 // this should just create a top level comment that is a reply to the original item
1116 if (!is_numeric($pid) || ($pid < 0)) {
1120 COM_updateSpeedlimit('comment');
1121 if (empty($title) || empty($comment)) {
1122 COM_errorLog("CMT_saveComment: $uid from {$_SERVER['REMOTE_ADDR']} tried "
1123 . 'to submit a comment with invalid $title and/or $comment.');
1125 } elseif (($_CONF['commentsubmission'] == 1) &&
1126 !SEC_hasRights('comment.submit')) {
1127 // comment into comment submission table enabled
1129 DB_save($_TABLES['commentsubmissions'],
1130 'sid,uid,name,comment,date,title,pid,ipaddress,type',
1131 "'$sid',$uid,'$name','$comment',NOW(),'$title',$pid,'{$_SERVER['REMOTE_ADDR']}','$type'");
1133 DB_save($_TABLES['commentsubmissions'],
1134 'sid,uid,comment,date,title,pid,ipaddress,type',
1135 "'$sid',$uid,'$comment',NOW(),'$title',$pid,'{$_SERVER['REMOTE_ADDR']}','$type'");
1138 $ret = -1; // comment queued
1139 } elseif ($pid > 0) {
1140 DB_lockTable ($_TABLES['comments']);
1142 $result = DB_query("SELECT rht, indent FROM {$_TABLES['comments']} WHERE cid = $pid "
1143 . "AND sid = '$sid'");
1144 list($rht, $indent) = DB_fetchArray($result);
1145 if ( !DB_error() ) {
1146 DB_query("UPDATE {$_TABLES['comments']} SET lft = lft + 2 "
1147 . "WHERE sid = '$sid' AND type = '$type' AND lft >= $rht");
1148 DB_query("UPDATE {$_TABLES['comments']} SET rht = rht + 2 "
1149 . "WHERE sid = '$sid' AND type = '$type' AND rht >= $rht");
1151 DB_save ($_TABLES['comments'], 'sid,uid,comment,date,title,pid,lft,rht,indent,type,ipaddress,name',
1152 "'$sid',$uid,'$comment',now(),'$title',$pid,$rht,$rht+1,$indent+1,'$type','{$_SERVER['REMOTE_ADDR']}','$name'");
1154 DB_save ($_TABLES['comments'], 'sid,uid,comment,date,title,pid,lft,rht,indent,type,ipaddress',
1155 "'$sid',$uid,'$comment',now(),'$title',$pid,$rht,$rht+1,$indent+1,'$type','{$_SERVER['REMOTE_ADDR']}'");
1158 } else { //replying to non-existent comment or comment in wrong article
1159 COM_errorLog("CMT_saveComment: $uid from {$_SERVER['REMOTE_ADDR']} tried "
1160 . 'to reply to a non-existent comment or the pid/sid did not match');
1161 $ret = 4; // Cannot return here, tables locked!
1164 $rht = DB_getItem($_TABLES['comments'], 'MAX(rht)', "sid = '$sid'");
1169 DB_save ($_TABLES['comments'], 'sid,uid,comment,date,title,pid,lft,rht,indent,type,ipaddress,name',
1170 "'$sid',$uid,'$comment',now(),'$title',$pid,$rht+1,$rht+2,0,'$type','{$_SERVER['REMOTE_ADDR']}','$name'");
1172 $rht = DB_getItem($_TABLES['comments'], 'MAX(rht)', "sid = '$sid'");
1176 DB_save ($_TABLES['comments'], 'sid,uid,comment,date,title,pid,lft,rht,indent,type,ipaddress',
1177 "'$sid',$uid,'$comment',now(),'$title',$pid,$rht+1,$rht+2,0,'$type','{$_SERVER['REMOTE_ADDR']}'");
1182 $cid = DB_insertId();
1183 DB_unlockTable($_TABLES['comments']);
1185 // notify of new comment
1186 if ($_CONF['allow_reply_notifications'] == 1 && $pid > 0 && $ret == 0) {
1187 $result = DB_query("SELECT cid, uid, deletehash FROM {$_TABLES['commentnotifications']} WHERE cid = $pid");
1188 $A = DB_fetchArray($result);
1190 CMT_sendReplyNotification($A);
1194 // save user notification information
1195 if (isset($_POST['notify']) && ($ret == -1 || $ret == 0) ) {
1196 $deletehash = md5($title . $cid . $comment . rand());
1198 //null goes into cid, comment not published yet, set moderation queue id
1199 DB_save($_TABLES['commentnotifications'], 'uid,deletehash,mid',"$uid,'$deletehash',$cid");
1201 DB_save($_TABLES['commentnotifications'], 'cid,uid,deletehash',"$cid,$uid,'$deletehash'");
1205 // Send notification of comment if no errors and notifications enabled
1207 if ((($ret == -1) || ($ret == 0)) && isset($_CONF['notification']) &&
1208 in_array('comment', $_CONF['notification'])) {
1210 $cid = 0; // comment went into the submission queue
1212 if (($uid == 1) && isset($username)) {
1213 CMT_sendNotification($title, $comment, $uid, $username,
1214 $_SERVER['REMOTE_ADDR'], $type, $cid);
1216 CMT_sendNotification($title, $comment, $uid, '',
1217 $_SERVER['REMOTE_ADDR'], $type, $cid);
1225 * Send an email notification for a new comment submission.
1227 * @param $title string comment title
1228 * @param $comment string text of the comment
1229 * @param $uid int user id
1230 * @param $username string optional name of anonymous user
1231 * @param $ipaddress string poster's IP address
1232 * @param $type string type of comment ('article', 'polls', ...)
1233 * @param $cid int comment id (or 0 when in submission queue)
1234 * @return boolean true if successfully sent, otherwise false
1237 function CMT_sendNotification($title, $comment, $uid, $username, $ipaddress, $type, $cid)
1239 global $_CONF, $_TABLES, $LANG01, $LANG03, $LANG08, $LANG09, $LANG29;
1242 if (($username == $_SERVER['REMOTE_ADDR']) &&
1243 ($ipaddress != $_SERVER['REMOTE_ADDR'])) {
1244 COM_errorLog("The API for CMT_sendNotification has changed ...");
1248 // we have to undo the addslashes() call from savecomment()
1249 $title = stripslashes($title);
1250 $comment = stripslashes($comment);
1252 // strip HTML if posted in HTML mode
1253 if (preg_match('/<.*>/', $comment) != 0) {
1254 $comment = strip_tags($comment);
1260 if (($uid == 1) && !empty($username)) {
1261 $author = $username;
1263 $author = COM_getDisplayName($uid);
1265 if (($uid == 1) && !empty($ipaddress)) {
1266 // add IP address for anonymous posters
1267 $author .= ' (' . $ipaddress . ')';
1270 $mailbody = "$LANG03[16]: $title\n"
1271 . "$LANG03[5]: $author\n";
1273 if ($type != 'article') {
1274 $mailbody .= "$LANG09[5]: $type\n";
1277 if ($_CONF['emailstorieslength'] > 0) {
1278 if ($_CONF['emailstorieslength'] > 1) {
1279 $comment = MBYTE_substr($comment, 0, $_CONF['emailstorieslength'])
1282 $mailbody .= $comment . "\n\n";
1286 $mailsubject = $_CONF['site_name'] . ' ' . $LANG29[41];
1287 $mailbody .= $LANG01[10] . ' <' . $_CONF['site_admin_url']
1288 . "/moderation.php>\n\n";
1290 $mailsubject = $_CONF['site_name'] . ' ' . $LANG03[9];
1291 $mailbody .= $LANG03[39] . ' <' . $_CONF['site_url']
1292 . '/comment.php?mode=view&cid=' . $cid . ">\n\n";
1295 $mailbody .= "\n------------------------------\n";
1296 $mailbody .= "\n$LANG08[34]\n";
1297 $mailbody .= "\n------------------------------\n";
1300 return COM_mail($_CONF['site_mail'], $mailsubject, $mailbody);
1304 * Deletes a given comment
1306 * The function expects the calling function to check to make sure the
1307 * requesting user has the correct permissions and that the comment exits
1308 * for the specified $type and $sid.
1310 * @author Vincent Furia, vinny01 AT users DOT sourceforge DOT net
1311 * @param string $type article, or plugin identifier
1312 * @param string $sid id of object comment belongs to
1313 * @param int $cid Comment ID
1314 * @return string 0 indicates success, >0 identifies problem
1316 function CMT_deleteComment ($cid, $sid, $type)
1318 global $_CONF, $_TABLES, $_USER;
1320 $ret = 0; // Assume good status unless reported otherwise
1322 // Sanity check, note we return immediately here and no DB operations
1324 if (!is_numeric ($cid) || ($cid < 0) || empty ($sid) || empty ($type)) {
1325 COM_errorLog("CMT_deleteComment: {$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried "
1326 . 'to delete a comment with one or more missing/bad values.');
1330 // Delete the comment from the DB and update the other comments to
1331 // maintain the tree structure
1332 // A lock is needed here to prevent other additions and/or deletions
1333 // from happening at the same time. A transaction would work better,
1334 // but aren't supported with MyISAM tables.
1335 DB_lockTable ($_TABLES['comments']);
1336 $result = DB_query("SELECT pid, lft, rht FROM {$_TABLES['comments']} "
1337 . "WHERE cid = $cid AND sid = '$sid' AND type = '$type'");
1338 if ( DB_numRows($result) == 1 ) {
1339 list($pid,$lft,$rht) = DB_fetchArray($result);
1340 DB_change ($_TABLES['comments'], 'pid', $pid, 'pid', $cid);
1341 DB_delete ($_TABLES['comments'], 'cid', $cid);
1342 DB_query("UPDATE {$_TABLES['comments']} SET indent = indent - 1 "
1343 . "WHERE sid = '$sid' AND type = '$type' AND lft BETWEEN $lft AND $rht");
1344 DB_query("UPDATE {$_TABLES['comments']} SET lft = lft - 2 "
1345 . "WHERE sid = '$sid' AND type = '$type' AND lft >= $rht");
1346 DB_query("UPDATE {$_TABLES['comments']} SET rht = rht - 2 "
1347 . "WHERE sid = '$sid' AND type = '$type' AND rht >= $rht");
1349 COM_errorLog("CMT_deleteComment: {$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried "
1350 . 'to delete a comment that doesn\'t exist as described.');
1354 DB_unlockTable ($_TABLES['comments']);
1360 * Display form to report abusive comment.
1362 * @param string $cid comment id
1363 * @param string $type type of comment ('article', 'polls', ...)
1364 * @return string HTML for the form (or error message)
1367 function CMT_reportAbusiveComment ($cid, $type)
1369 global $_CONF, $_TABLES, $_USER, $LANG03, $LANG12, $LANG_LOGIN;
1373 if (empty ($_USER['username'])) {
1374 $retval .= COM_startBlock ($LANG_LOGIN[1], '',
1375 COM_getBlockTemplate ('_msg_block', 'header'));
1376 $loginreq = new Template ($_CONF['path_layout'] . 'submit');
1377 $loginreq->set_file ('loginreq', 'submitloginrequired.thtml');
1378 $loginreq->set_var ('xhtml', XHTML);
1379 $loginreq->set_var ('login_message', $LANG_LOGIN[2]);
1380 $loginreq->set_var ('site_url', $_CONF['site_url']);
1381 $loginreq->set_var ('lang_login', $LANG_LOGIN[3]);
1382 $loginreq->set_var ('lang_newuser', $LANG_LOGIN[4]);
1383 $loginreq->parse ('errormsg', 'loginreq');
1384 $retval .= $loginreq->finish ($loginreq->get_var ('errormsg'));
1385 $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
1390 COM_clearSpeedlimit ($_CONF['speedlimit'], 'mail');
1391 $last = COM_checkSpeedlimit ('mail');
1393 $retval .= COM_startBlock ($LANG12[26], '',
1394 COM_getBlockTemplate ('_msg_block', 'header'))
1395 . $LANG12[30] . $last . $LANG12[31]
1396 . COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
1401 $start = new Template($_CONF['path_layout'] . 'comment');
1402 $start->set_file(array('report' => 'reportcomment.thtml'));
1403 $start->set_var('xhtml', XHTML);
1404 $start->set_var('site_url', $_CONF['site_url']);
1405 $start->set_var('layout_url', $_CONF['layout_url']);
1406 $start->set_var('lang_report_this', $LANG03[25]);
1407 $start->set_var('lang_send_report', $LANG03[10]);
1408 $start->set_var('cid', $cid);
1409 $start->set_var('type', $type);
1410 $start->set_var('gltoken_name', CSRF_TOKEN);
1411 $start->set_var('gltoken', SEC_createToken());
1413 $result = DB_query ("SELECT uid,sid,pid,title,comment,UNIX_TIMESTAMP(date) AS nice_date FROM {$_TABLES['comments']} WHERE cid = $cid AND type = '$type'");
1414 $A = DB_fetchArray ($result);
1416 $result = DB_query ("SELECT username,fullname,photo,email FROM {$_TABLES['users']} WHERE uid = {$A['uid']}");
1417 $B = DB_fetchArray ($result);
1419 // prepare data for comment preview
1422 $A['username'] = $B['username'];
1423 $A['fullname'] = $B['fullname'];
1424 $A['photo'] = $B['photo'];
1425 $A['email'] = $B['email'];
1429 $thecomment = CMT_getComment ($A, 'flat', $type, 'ASC', false, true);
1430 $start->set_var ('comment', $thecomment);
1431 $retval .= COM_startBlock ($LANG03[15])
1432 . $start->finish ($start->parse ('output', 'report'))
1439 * Send report about abusive comment
1441 * @param string $cid comment id
1442 * @param string $type type of comment ('article', 'polls', ...)
1443 * @return string Meta refresh or HTML for error message
1446 function CMT_sendReport ($cid, $type)
1448 global $_CONF, $_TABLES, $_USER, $LANG03, $LANG08, $LANG_LOGIN;
1450 if (empty ($_USER['username'])) {
1451 $retval = COM_siteHeader ('menu', $LANG_LOGIN[1]);
1452 $retval .= COM_startBlock ($LANG_LOGIN[1], '',
1453 COM_getBlockTemplate ('_msg_block', 'header'));
1454 $loginreq = new Template ($_CONF['path_layout'] . 'submit');
1455 $loginreq->set_file ('loginreq', 'submitloginrequired.thtml');
1456 $loginreq->set_var ('xhtml', XHTML);
1457 $loginreq->set_var ('login_message', $LANG_LOGIN[2]);
1458 $loginreq->set_var ('site_url', $_CONF['site_url']);
1459 $loginreq->set_var ('lang_login', $LANG_LOGIN[3]);
1460 $loginreq->set_var ('lang_newuser', $LANG_LOGIN[4]);
1461 $loginreq->parse ('errormsg', 'loginreq');
1462 $retval .= $loginreq->finish ($loginreq->get_var ('errormsg'));
1463 $retval .= COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'));
1464 $retval .= COM_siteFooter ();
1469 COM_clearSpeedlimit ($_CONF['speedlimit'], 'mail');
1470 if (COM_checkSpeedlimit ('mail') > 0) {
1471 return COM_refresh ($_CONF['site_url'] . '/index.php');
1474 $username = DB_getItem ($_TABLES['users'], 'username',
1475 "uid = {$_USER['uid']}");
1476 $result = DB_query ("SELECT uid,title,comment,sid,ipaddress FROM {$_TABLES['comments']} WHERE cid = $cid AND type = '$type'");
1477 $A = DB_fetchArray ($result);
1479 $title = stripslashes ($A['title']);
1480 $comment = stripslashes ($A['comment']);
1482 // strip HTML if posted in HTML mode
1483 if (preg_match ('/<.*>/', $comment) != 0) {
1484 $comment = strip_tags ($comment);
1487 $author = COM_getDisplayName ($A['uid']);
1488 if (($A['uid'] <= 1) && !empty ($A['ipaddress'])) {
1489 // add IP address for anonymous posters
1490 $author .= ' (' . $A['ipaddress'] . ')';
1493 $mailbody = sprintf ($LANG03[26], $username);
1495 . "$LANG03[16]: $title\n"
1496 . "$LANG03[5]: $author\n";
1498 if ($type != 'article') {
1499 $mailbody .= "$LANG09[5]: $type\n";
1502 if ($_CONF['emailstorieslength'] > 0) {
1503 if ($_CONF['emailstorieslength'] > 1) {
1504 $comment = MBYTE_substr ($comment, 0, $_CONF['emailstorieslength'])
1507 $mailbody .= $comment . "\n\n";
1510 $mailbody .= $LANG08[33] . ' <' . $_CONF['site_url']
1511 . '/comment.php?mode=view&cid=' . $cid . ">\n\n";
1513 $mailbody .= "\n------------------------------\n";
1514 $mailbody .= "\n$LANG08[34]\n";
1515 $mailbody .= "\n------------------------------\n";
1517 $mailsubject = $_CONF['site_name'] . ' ' . $LANG03[27];
1519 if (COM_mail ($_CONF['site_mail'], $mailsubject, $mailbody)) {
1520 $msg = 27; // message sent
1522 $msg = 85; // problem sending the email
1524 COM_updateSpeedlimit ('mail');
1526 return COM_refresh ($_CONF['site_url'] . "/index.php?msg=$msg");
1530 * Handles a comment edit submission
1532 * @copyright Jared Wenerd 2008
1533 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1534 * @param string $mode whether to store edited comment in the queue
1535 * @return string HTML (possibly a refresh)
1537 function CMT_handleEditSubmit($mode = null)
1539 global $_CONF, $_TABLES, $_USER, $LANG03;
1543 $type = COM_applyFilter($_POST['type']);
1544 $sid = COM_applyFilter($_POST['sid']);
1545 $cid = COM_applyFilter($_POST['cid']);
1546 $postmode = COM_applyFilter($_POST['postmode']);
1548 $commentuid = DB_getItem ($_TABLES['comments'], 'uid', "cid = '$cid'");
1549 if ( empty($_USER['uid'])) {
1552 $uid = $_USER['uid'];
1555 // check for bad input
1556 if (empty($sid) || empty($_POST['title']) || empty($_POST['comment']) ||
1557 !is_numeric($cid) || ($cid < 1)) {
1558 COM_errorLog("CMT_handleEditSubmit(): {{$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried to edit a comment with one or more missing values.");
1559 return COM_refresh($_CONF['site_url'] . '/index.php');
1560 } elseif ( $uid != $commentuid && !SEC_hasRights( 'comment.moderate' ) ) {
1562 COM_errorLog("CMT_handleEditSubmit(): {{$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried "
1563 . 'to edit a comment without proper permission.');
1564 return COM_refresh($_CONF['site_url'] . '/index.php');
1567 $comment = CMT_prepareText($_POST['comment'], $postmode, $type);
1568 $title = COM_checkWords (strip_tags (COM_stripslashes ($_POST['title'])));
1570 if ($mode == $LANG03[35]) {
1571 $table = $_TABLES['commentsubmissions'];
1573 $table = $_TABLES['comments'];
1576 if (!empty ($title) && !empty ($comment)) {
1577 COM_updateSpeedlimit ('comment');
1578 $title = addslashes ($title);
1579 $comment = addslashes ($comment);
1581 // save the comment into the table
1582 DB_query("UPDATE $table SET comment = '$comment', title = '$title'"
1583 . " WHERE cid=$cid AND sid='$sid'");
1585 if (DB_error() ) { //saving to non-existent comment or comment in wrong article
1586 COM_errorLog("CMT_handleEditSubmit(): {$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried "
1587 . 'to edit to a non-existent comment or the cid/sid did not match');
1588 return COM_refresh($_CONF['site_url'] . '/index.php');
1590 //save edit information for published comment
1591 if ($mode != $LANG03[35]) {
1592 DB_save($_TABLES['commentedits'],'cid,uid,time',"$cid,$uid,NOW()");
1594 return COM_refresh (COM_buildUrl ($_CONF['site_admin_url'] . "/moderation.php"));
1598 COM_errorLog("CMT_handleEditSubmit(): {$_USER['uid']} from {$_SERVER['REMOTE_ADDR']} tried "
1599 . 'to submit a comment with invalid $title and/or $comment.');
1600 return COM_refresh($_CONF['site_url'] . '/index.php');
1603 return COM_refresh(COM_buildUrl($_CONF['site_url']
1604 . "/article.php?story=$sid"));
1608 * Filters comment text and appends necessary tags (sig and/or edit)
1610 * @copyright Jared Wenerd 2008
1611 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1612 * @param string $comment comment text
1613 * @param string $postmode ('html', 'plaintext', ...)
1614 * @param string $type Type of item (article, polls, etc.)
1615 * @param bool $edit if true append edit tag
1616 * @param int $cid commentid if editing comment (for proper sig)
1617 * @return string of comment text
1619 function CMT_prepareText($comment, $postmode, $type, $edit = false, $cid = null)
1621 global $_USER, $_TABLES, $LANG03, $_CONF;
1623 if ($postmode == 'html') {
1624 $html_perm = ($type == 'article') ? 'story.edit' : "$type.edit";
1625 $comment = COM_checkWords(COM_checkHTML(COM_stripslashes($comment),
1629 $comment = htmlspecialchars(COM_checkWords(COM_stripslashes($comment)));
1630 $newcomment = COM_makeClickableLinks ($comment);
1631 if (strcmp ($comment, $newcomment) != 0) {
1632 $comment = nl2br ($newcomment);
1637 $comment .= '<div class="comment-edit">' . $LANG03[30] . ' '
1638 . strftime($_CONF['date'], time()) . ' ' .$LANG03[31] .' '
1639 . $_USER['username'] . '</div><!-- /COMMENTEDIT -->';
1644 if (empty ($_USER['uid'])) {
1646 } elseif ($edit && is_numeric($cid) ){
1647 //if comment moderator
1648 $uid = DB_getItem ($_TABLES['comments'], 'uid', "cid = '$cid'");
1650 $uid = $_USER['uid'];
1655 $sig = DB_getItem ($_TABLES['users'], 'sig', "uid = '$uid'");
1656 if (!empty ($sig)) {
1657 $comment .= '<!-- COMMENTSIG --><div class="comment-sig">';
1658 if ( $postmode == 'html') {
1659 $comment .= '---<br' . XHTML . '>' . nl2br($sig);
1661 $comment .= '---' . LB . $sig;
1663 $comment .= '</div><!-- /COMMENTSIG -->';
1671 * Disables comments for all stories where current time is past comment expire
1672 * time and enables comments for certain number of most recent stories.
1674 * @copyright Jared Wenerd 2008
1675 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1677 function CMT_updateCommentcodes()
1679 global $_CONF, $_TABLES;
1681 if ($_CONF['comment_close_rec_stories'] > 0) {
1682 $results = DB_query("SELECT sid FROM {$_TABLES['stories']} WHERE (date <= NOW()) AND (draft_flag = 0) ORDER BY date DESC LIMIT {$_CONF['comment_close_rec_stories']}");
1683 while ($A = DB_fetchArray($results)) {
1684 $allowedcomments[] = $A['sid'];
1686 // update comment codes
1688 if (count($allowedcomments) > 1) {
1689 $sql .= "sid NOT IN ('" . implode("','", $allowedcomments) . "')";
1691 $sql .= "sid <> '$sid'";
1693 $sql = "UPDATE {$_TABLES['stories']} SET commentcode = 1 WHERE (commentcode = 0) AND (date < NOW()) AND (draft_flag = 0)" . $sql;
1697 $sql = "UPDATE {$_TABLES['stories']} SET commentcode = 1 WHERE UNIX_TIMESTAMP(comment_expire) < UNIX_TIMESTAMP() AND UNIX_TIMESTAMP(comment_expire) <> 0";
1702 * Rebuilds hierarchical data of comments after moderation using recursion.
1704 * @copyright Jared Wenerd 2008
1705 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1706 * @param string $sid id of object comment belongs to
1707 * @param int $pid id of parent comment
1708 * @param int $left id of left-hand successor
1709 * @return int id of right-hand successor
1710 * @see CMT_deleteComment
1713 function CMT_rebuildTree($sid, $pid = 0, $left = 0)
1718 $result = DB_query ("SELECT cid FROM {$_TABLES['comments']} WHERE sid = '$sid' AND pid = $pid ORDER BY date ASC");
1719 while (DB_numRows($result) != 0 && $A = DB_fetchArray ($result)) {
1720 $right = CMT_rebuildTree($sid, $A['cid'], $right);
1724 DB_query ("UPDATE {$_TABLES['comments']} SET lft = $left, rht = $right WHERE cid = $pid");
1731 * Moves comment from submission table to comments table
1733 * @copyright Jared Wenerd 2008
1734 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1735 * @param string $cid comment id
1736 * @return string of story id
1738 function CMT_approveModeration($cid)
1740 global $_CONF, $_TABLES;
1742 $result = DB_query("SELECT type, sid, date, title, comment, uid, name, pid, ipaddress FROM {$_TABLES['commentsubmissions']} WHERE cid = '$cid'");
1743 $A = DB_fetchArray($result);
1745 if ($A['pid'] > 0) {
1746 // get indent+1 of parent
1747 $indent = DB_getItem($_TABLES['comments'], 'indent+1',
1748 "cid = '{$A['pid']}'");
1753 $A['title'] = addslashes($A['title']);
1754 $A['comment'] = addslashes($A['comment']);
1756 if (isset($A['name'])) {
1758 $A['name'] = addslashes($A['name']);
1759 DB_save($_TABLES['comments'], 'type,sid,date,title,comment,uid,name,pid,ipaddress,indent',
1760 "'{$A['type']}','{$A['sid']}','{$A['date']}','{$A['title']}','{$A['comment']}','{$A['uid']}',".
1761 "'{$A['name']}','{$A['pid']}','{$A['ipaddress']}',$indent");
1763 // insert data, null automatically goes into name column
1764 DB_save($_TABLES['comments'], 'type,sid,date,title,comment,uid,pid,ipaddress,indent',
1765 "'{$A['type']}','{$A['sid']}','{$A['date']}','{$A['title']}','{$A['comment']}','{$A['uid']}',".
1766 "'{$A['pid']}','{$A['ipaddress']}',$indent");
1768 $newcid = DB_insertId();
1770 DB_delete($_TABLES['commentsubmissions'], 'cid', $cid);
1772 DB_change($_TABLES['commentnotifications'], 'cid', $newcid, 'mid', $cid);
1774 // notify of new published comment
1775 if ($_CONF['allow_reply_notifications'] == 1 && $A['pid'] > 0) {
1776 $result = DB_query("SELECT cid, uid, deletehash FROM {$_TABLES['commentnotifications']} WHERE cid = {$A['pid']}");
1777 $B = DB_fetchArray($result);
1779 CMT_sendReplyNotification($B);
1787 * Sends a notification of new comment reply
1789 * @param array $A contains cid, uid, and deletekey
1790 * @param boolean $send_self send notification when replying to self?
1791 * @copyright Jared Wenerd 2008
1792 * @author Jared Wenerd, wenerd87 AT gmail DOT com
1794 function CMT_sendReplyNotification($A, $send_self = false)
1796 global $_CONF, $_TABLES, $_USER, $LANG03;
1798 if (($_USER['uid'] != $A['uid']) || $send_self) {
1800 $name = COM_getDisplayName($A['uid']);
1801 $title = DB_getItem($_TABLES['comments'], 'title', "cid = {$A['cid']}");
1802 $commenturl = $_CONF['site_url'] . '/comment.php';
1804 $mailsubject = $_CONF['site_name'] . ': ' . $LANG03[37];
1806 $mailbody = sprintf($LANG03[41], $name) . LB . LB;
1807 $mailbody .= sprintf($LANG03[38], $title) . LB . LB;
1808 $mailbody .= $LANG03[39] . LB . '<' . $commenturl . '?mode=view&cid='
1809 . $A['cid'] . '&format=nested' . '>' . LB . LB;
1810 $mailbody .= $LANG03[40] . LB . '<' . $commenturl
1811 . '?mode=unsubscribe&key=' . $A['deletehash'] . '>' . LB;
1813 $email = DB_getItem($_TABLES['users'], 'email', "uid = {$A['uid']}");
1814 if (!empty($email)) {
1815 COM_mail($email, $mailsubject, $mailbody);