4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5 * Copyright (C) 2002-2009 The Nucleus Group
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 * (see nucleus/documentation/index.html#license for more info)
14 * A class representing the comments (all of them) for a certain post on a ceratin blog
16 * @license http://nucleuscms.org/license.txt GNU General Public License
17 * @copyright Copyright (C) 2002-2009 The Nucleus Group
18 * @version $Id: COMMENTS.php 1527 2011-06-21 10:43:44Z sakamocchi $
21 if ( !function_exists('requestVar') ) exit;
22 require_once dirname(__FILE__) . '/COMMENTACTIONS.php';
26 // reference to the itemActions object that is calling the showComments function
29 // item for which comment are being displayed
32 // total amount of comments displayed
36 * Comments::__construct()
37 * Creates a new Comments object for the given blog and item
39 * @param integer $itemid id of the item
42 public function __construct($itemid)
44 $this->itemid = (integer) $itemid;
49 * Comments::setItemActions()
50 * Used when parsing comments
52 * @param object $itemActions itemActions object, that will take care of the parsing
55 public function setItemActions(&$itemActions)
57 $this->itemActions =& $itemActions;
62 * Comments::showComments()
63 * Shows maximum $max comments to the given item using the given template
64 * returns the amount of shown comments (if maxToShow = -1, then there is no limit)
66 * @param array template template to use
67 * @param integer maxToShow max. comments to show
68 * @param integer showNone indicates if the 'no comments' thingie should be outputted
69 * when there are no comments (useful for closed items)
70 * @param string highlight Highlight to use (if any)
71 * @return integer number of comments
73 public function showComments($template, $maxToShow = -1, $showNone = 1, $highlight = '')
75 global $CONF, $manager;
77 if ( $maxToShow == 0 )
79 $this->commentcount = $this->amountComments();
83 $query = 'SELECT citem as itemid, cnumber as commentid, cbody as body, cuser as user, cmail as userid, '
84 . 'cemail as email, cmember as memberid, ctime, chost as host, cip as ip, cblog as blogid '
85 . 'FROM %s as c WHERE citem=%d ORDER BY ctime';
87 $query = sprintf($query, sql_table('comment'), (integer) $this->itemid);
88 $comments = DB::getResult($query);
89 $this->commentcount = $comments->rowCount();
92 // create parser object & action handler
93 $handler = new CommentActions($this);
94 $handler->setTemplate($template);
96 $parser = new Parser($handler);
98 // if no result was found
99 if ( $this->commentcount == 0 )
101 // note: when no reactions, COMMENTS_HEADER and COMMENTS_FOOTER are _NOT_ used
104 $parser->parse($template['COMMENTS_NONE']);
109 // if too many comments to show
110 if ( ($maxToShow != -1) && ($this->commentcount > $maxToShow) )
112 $parser->parse($template['COMMENTS_TOOMUCH']);
116 $parser->parse($template['COMMENTS_HEADER']);
118 foreach ( $comments as $comment )
120 $comment['timestamp'] = strtotime($comment['ctime']);
121 $handler->setCurrentComment($comment);
122 $handler->setHighlight($highlight);
124 $data = array('comment' => &$comment);
125 $manager->notify('PreComment', $data);
126 $parser->parse($template['COMMENTS_BODY']);
127 $manager->notify('PostComment', $data);
130 $parser->parse($template['COMMENTS_FOOTER']);
132 $comments->closeCursor();
134 return $this->commentcount;
138 * Comments::amountComments()
139 * Returns the amount of comments for this itemid
142 * @return integer number of comments
144 public function amountComments()
146 $query = 'SELECT COUNT(*) FROM %s WHERE citem=%d;';
147 $query = sprintf($query, sql_table('comment'), (integer) $this->itemid);
148 $res = DB::getValue($query);
154 * Comments::addComment()
155 * Adds a new comment to the database
157 * @param string $timestamp
158 * @param array $comment
161 public function addComment($timestamp, $comment)
163 global $CONF, $member, $manager;
165 $blogid = getBlogIDFromItemID($this->itemid);
167 $settings =& $manager->getBlog($blogid);
168 $settings->readSettings();
170 // begin if: comments disabled
171 if ( !$settings->commentsEnabled() )
173 return _ERROR_COMMENTS_DISABLED;
176 // begin if: public cannot comment
177 if ( !$settings->isPublic() && !$member->isLoggedIn() )
179 return _ERROR_COMMENTS_NONPUBLIC;
182 // begin if: comment uses a protected member name
183 if ( $CONF['ProtectMemNames'] && !$member->isLoggedIn() && Member::isNameProtected($comment['user']) )
185 return _ERROR_COMMENTS_MEMBERNICK;
188 // begin if: email required, but missing (doesn't apply to members)
189 if ( $settings->emailRequired() && i18n::strlen($comment['email']) == 0 && !$member->isLoggedIn() )
191 return _ERROR_EMAIL_REQUIRED;
194 // begin if: commenter's name is too long
195 if ( i18n::strlen($comment['user']) > 40 )
197 return _ERROR_USER_TOO_LONG;
200 // begin if: commenter's email is too long
201 if ( i18n::strlen($comment['email']) > 100 )
203 return _ERROR_EMAIL_TOO_LONG;
206 // begin if: commenter's url is too long
207 if ( i18n::strlen($comment['userid']) > 100 )
209 return _ERROR_URL_TOO_LONG;
212 $comment['timestamp'] = $timestamp;
213 $comment['host'] = gethostbyaddr(serverVar('REMOTE_ADDR') );
214 $comment['ip'] = serverVar('REMOTE_ADDR');
216 // begin if: member is logged in, use that data
217 if ( $member->isLoggedIn() )
219 $comment['memberid'] = $member->getID();
220 $comment['user'] = '';
221 $comment['userid'] = '';
222 $comment['email'] = '';
226 $comment['memberid'] = 0;
233 if ( isset($manager->subscriptions['ValidateForm']) )
235 $plugins = array_merge($plugins, $manager->subscriptions['ValidateForm']);
238 if ( isset($manager->subscriptions['PreAddComment']) )
240 $plugins = array_merge($plugins, $manager->subscriptions['PreAddComment']);
243 if ( isset($manager->subscriptions['PostAddComment']) )
245 $plugins = array_merge($plugins, $manager->subscriptions['PostAddComment']);
248 $plugins = array_unique($plugins);
250 while ( list(, $plugin) = each($plugins) )
252 $p = $manager->getPlugin($plugin);
253 $continue = $continue || $p->supportsFeature('handleSpam');
258 'body' => $comment['body'],
259 'id' => $comment['itemid'],
261 'return' => $continue
264 // begin if: member logged in
265 if ( $member->isLoggedIn() )
267 $spamcheck['author'] = $member->displayname;
268 $spamcheck['email'] = $member->email;
273 $spamcheck['author'] = $comment['user'];
274 $spamcheck['email'] = $comment['email'];
275 $spamcheck['url'] = $comment['userid'];
278 $data = array('spamcheck' => &$spamcheck);
279 $manager->notify('SpamCheck', $data);
281 if ( !$continue && isset($spamcheck['result']) && $spamcheck['result'] == TRUE )
283 return _ERROR_COMMENTS_SPAM;
286 // isValidComment returns either "1" or an error message
287 $isvalid = $this->isValidComment($comment, $spamcheck);
293 // begin if: send email to notification address
294 if ( $settings->getNotifyAddress() && $settings->notifyOnComment() )
297 $message = _NOTIFY_NC_MSG . ' ' . $this->itemid . "\n";
298 $temp = parse_url($CONF['Self']);
300 if ( $temp['scheme'] )
302 $message .= Link::create_item_link($this->itemid) . "\n\n";
306 $tempurl = $settings->getURL();
308 if ( i18n::substr($tempurl, -1) == '/' || i18n::substr($tempurl, -4) == '.php' )
310 $message .= $tempurl . '?itemid=' . $this->itemid . "\n\n";
314 $message .= $tempurl . '/?itemid=' . $this->itemid . "\n\n";
318 if ( $comment['memberid'] == 0 )
320 $message .= _NOTIFY_USER . ' ' . $comment['user'] . "\n";
321 $message .= _NOTIFY_USERID . ' ' . $comment['userid'] . "\n";
325 $message .= _NOTIFY_MEMBER .' ' . $member->getDisplayName() . ' (ID=' . $member->getID() . ")\n";
328 $message .= _NOTIFY_HOST . ' ' . $comment['host'] . "\n";
329 $message .= _NOTIFY_COMMENT . "\n " . $comment['body'] . "\n";
330 $message .= NOTIFICATION::get_mail_footer();
332 $item =& $manager->getItem($this->itemid, 0, 0);
333 $subject = _NOTIFY_NC_TITLE . ' ' . strip_tags($item['title']) . ' (' . $this->itemid . ')';
335 $from = $member->getNotifyFromMailAddress($comment['email']);
337 NOTIFICATION::mail($settings->getNotifyAddress(), $subject, $message, $from, i18n::get_current_charset());
340 $comment = Comment::prepare($comment);
342 $data = array('comment' => &$comment, 'spamcheck' => &$spamcheck);
343 $manager->notify('PreAddComment', $data);
345 $name = DB::quoteValue($comment['user']);
346 $url = DB::quoteValue($comment['userid']);
347 $email = DB::quoteValue($comment['email']);
348 $body = DB::quoteValue($comment['body']);
349 $host = DB::quoteValue($comment['host']);
350 $ip = DB::quoteValue($comment['ip']);
351 $memberid = intval($comment['memberid']);
352 $timestamp = DB::formatDateTime($comment['timestamp']);
353 $itemid = $this->itemid;
355 $qSql = 'SELECT COUNT(*) AS result '
356 . 'FROM ' . sql_table('comment')
359 . ' AND cmember = ' . $memberid
360 . ' AND cbody = ' . $body
361 . ' AND citem = ' . $itemid
362 . ' AND cblog = ' . $blogid;
363 $result = (integer) DB::getValue($qSql);
367 return _ERROR_BADACTION;
370 $query = sprintf('INSERT INTO %s (cuser, cmail, cemail, cmember, cbody, citem, ctime, chost, cip, cblog) '
371 . 'VALUES (%s, %s, %s, %d, %s, %d, %s, %s, %s, %d)'
372 , sql_table('comment'), $name, $url, $email, $memberid, $body, $itemid, $timestamp, $host, $ip, $blogid);
377 $commentid = DB::getInsertId();
378 $data = array('comment' => &$comment, 'commentid' => &$commentid, 'spamcheck' => &$spamcheck);
379 $manager->notify('PostAddComment', $data);
386 * Comments::isValidComment()
387 * Checks if a comment is valid and call plugins
388 * that can check if the comment is a spam comment
390 * @param array $comment array with comment elements
391 * @param array $spamcheck array with spamcheck elements
392 * @return boolean valid or not
394 private function isValidComment(&$comment, &$spamcheck)
396 global $member, $manager;
398 // check if there exists a item for this date
399 $item =& $manager->getItem($this->itemid, 0, 0);
403 return _ERROR_NOSUCHITEM;
406 if ( $item['closed'] )
408 return _ERROR_ITEMCLOSED;
411 // don't allow words that are too long
412 if ( preg_match('/[a-zA-Z0-9|\.,;:!\?=\/\\\\]{90,90}/', $comment['body']) != 0 )
414 return _ERROR_COMMENT_LONGWORD;
417 // check lengths of comment
418 if ( i18n::strlen($comment['body']) < 3 )
420 return _ERROR_COMMENT_NOCOMMENT;
423 if ( i18n::strlen($comment['body']) > 5000 )
425 return _ERROR_COMMENT_TOOLONG;
428 // only check username if no member logged in
429 if ( !$member->isLoggedIn() && (i18n::strlen($comment['user']) < 2) )
431 return _ERROR_COMMENT_NOUSERNAME;
434 if ( (i18n::strlen($comment['email']) != 0) && !NOTIFICATION::address_validation(trim($comment['email'])) )
436 return _ERROR_BADMAILADDRESS;
439 // let plugins do verification (any plugin which thinks the comment is invalid
440 // can change 'error' to something other than '1')
442 $data = array('type' => 'comment', 'comment' => &$comment, 'error' => &$result, 'spamcheck' => &$spamcheck);
443 $manager->notify('ValidateForm', $data);