OSDN Git Service

932e589edbf0c8a935b1ce632ca5d550eb0cf45e
[nucleus-jp/nucleus-next.git] / nucleus / libs / COMMENTS.php
1 <?php
2
3 /*
4  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5  * Copyright (C) 2002-2009 The Nucleus Group
6  *
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)
12  */
13 /**
14  * A class representing the comments (all of them) for a certain post on a ceratin blog
15  *
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 $
19  */
20
21 if ( !function_exists('requestVar') ) exit;
22 require_once dirname(__FILE__) . '/COMMENTACTIONS.php';
23
24 class Comments
25 {
26         // reference to the itemActions object that is calling the showComments function
27         public $itemActions;
28         
29         // item for which comment are being displayed
30         public $itemid;
31         
32         // total amount of comments displayed
33         public $commentcount;
34         
35         /**
36          * Comments::__construct()
37          * Creates a new Comments object for the given blog and item
38          *
39          * @param       integer $itemid id of the item
40          * @return      void
41          */
42         public function __construct($itemid)
43         {
44                 $this->itemid = (integer) $itemid;
45                 return;
46         }
47         
48         /**
49          * Comments::setItemActions()
50          * Used when parsing comments
51          *
52          * @param       object  $itemActions    itemActions object, that will take care of the parsing
53          * @return      void
54          */
55         public function setItemActions(&$itemActions)
56         {
57                 $this->itemActions =& $itemActions;
58                 return;
59         }
60         
61         /**
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)
65          *
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
72          */
73         public function showComments($template, $maxToShow = -1, $showNone = 1, $highlight = '')
74         {
75                 global $CONF, $manager;
76                 
77                 if ( $maxToShow == 0 )
78                 {
79                         $this->commentcount = $this->amountComments();
80                 }
81                 else
82                 {
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';
86                         
87                         $query = sprintf($query, sql_table('comment'), (integer) $this->itemid);
88                         $comments = DB::getResult($query);
89                         $this->commentcount = $comments->rowCount();
90                 }
91                 
92                 // create parser object & action handler
93                 $handler = new CommentActions($this);
94                 $handler->setTemplate($template);
95                 
96                 $parser = new Parser($handler);
97                 
98                 // if no result was found
99                 if ( $this->commentcount == 0 )
100                 {
101                         // note: when no reactions, COMMENTS_HEADER and COMMENTS_FOOTER are _NOT_ used
102                         if ( $showNone )
103                         {
104                                 $parser->parse($template['COMMENTS_NONE']);
105                         }
106                         return 0;
107                 }
108                 
109                 // if too many comments to show
110                 if ( ($maxToShow != -1) && ($this->commentcount > $maxToShow) )
111                 {
112                         $parser->parse($template['COMMENTS_TOOMUCH']);
113                         return 0;
114                 }
115                 
116                 $parser->parse($template['COMMENTS_HEADER']);
117                 
118                 foreach ( $comments as $comment )
119                 {
120                         $comment['timestamp'] = strtotime($comment['ctime']);
121                         $handler->setCurrentComment($comment);
122                         $handler->setHighlight($highlight);
123                         
124                         $manager->notify('PreComment', array('comment' => &$comment));
125                         $parser->parse($template['COMMENTS_BODY']);
126                         $manager->notify('PostComment', array('comment' => &$comment));
127                 }
128                 
129                 $parser->parse($template['COMMENTS_FOOTER']);
130                 
131                 $comments->closeCursor();
132                 
133                 return $this->commentcount;
134         }
135         
136         /**
137          * Comments::amountComments()
138          * Returns the amount of comments for this itemid
139          * 
140          * @param       void
141          * @return      integer number of comments
142          */
143         public function amountComments()
144         {
145                 $query = 'SELECT COUNT(*) FROM %s WHERE citem=%d;';
146                 $query = sprintf($query, sql_table('comment'), (integer) $this->itemid);
147                 $res = DB::getValue($query);
148                 
149                 return $res;
150         }
151         
152         /**
153          * Comments::addComment()
154          * Adds a new comment to the database
155          * 
156          * @param string $timestamp
157          * @param array $comment
158          * @return mixed
159          */
160         public function addComment($timestamp, $comment)
161         {
162                 global $CONF, $member, $manager;
163                 
164                 $blogid = getBlogIDFromItemID($this->itemid);
165                 
166                 $settings =& $manager->getBlog($blogid);
167                 $settings->readSettings();
168                 
169                 // begin if: comments disabled
170                 if ( !$settings->commentsEnabled() )
171                 {
172                         return _ERROR_COMMENTS_DISABLED;
173                 }
174                 
175                 // begin if: public cannot comment
176                 if ( !$settings->isPublic() && !$member->isLoggedIn() )
177                 {
178                         return _ERROR_COMMENTS_NONPUBLIC;
179                 }
180                 
181                 // begin if: comment uses a protected member name
182                 if ( $CONF['ProtectMemNames'] && !$member->isLoggedIn() && Member::isNameProtected($comment['user']) )
183                 {
184                         return _ERROR_COMMENTS_MEMBERNICK;
185                 }
186                 
187                 // begin if: email required, but missing (doesn't apply to members)
188                 if ( $settings->emailRequired() && i18n::strlen($comment['email']) == 0 && !$member->isLoggedIn() )
189                 {
190                         return _ERROR_EMAIL_REQUIRED;
191                 }
192                 
193                 // begin if: commenter's name is too long
194                 if ( i18n::strlen($comment['user']) > 40 )
195                 {
196                         return _ERROR_USER_TOO_LONG;
197                 }
198                 
199                 // begin if: commenter's email is too long
200                 if ( i18n::strlen($comment['email']) > 100 )
201                 {
202                         return _ERROR_EMAIL_TOO_LONG;
203                 }
204                 
205                 // begin if: commenter's url is too long
206                 if ( i18n::strlen($comment['userid']) > 100 )
207                 {
208                         return _ERROR_URL_TOO_LONG;
209                 }
210                 
211                 $comment['timestamp'] = $timestamp;
212                 $comment['host'] = gethostbyaddr(serverVar('REMOTE_ADDR') );
213                 $comment['ip'] = serverVar('REMOTE_ADDR');
214                 
215                 // begin if: member is logged in, use that data
216                 if ( $member->isLoggedIn() )
217                 {
218                         $comment['memberid'] = $member->getID();
219                         $comment['user'] = '';
220                         $comment['userid'] = '';
221                         $comment['email'] = '';
222                 }
223                 else
224                 {
225                         $comment['memberid'] = 0;
226                 }
227                 
228                 // spam check
229                 $continue = FALSE;
230                 $plugins = array();
231                 
232                 if ( isset($manager->subscriptions['ValidateForm']) )
233                 {
234                         $plugins = array_merge($plugins, $manager->subscriptions['ValidateForm']);
235                 }
236                 
237                 if ( isset($manager->subscriptions['PreAddComment']) )
238                 {
239                         $plugins = array_merge($plugins, $manager->subscriptions['PreAddComment']);
240                 }
241                 
242                 if ( isset($manager->subscriptions['PostAddComment']) )
243                 {
244                         $plugins = array_merge($plugins, $manager->subscriptions['PostAddComment']);
245                 }
246                 
247                 $plugins = array_unique($plugins);
248                 
249                 while ( list(, $plugin) = each($plugins) )
250                 {
251                         $p = $manager->getPlugin($plugin);
252                         $continue = $continue || $p->supportsFeature('handleSpam');
253                 }
254                 
255                 $spamcheck = array(
256                         'type'          => 'comment',
257                         'body'          => $comment['body'],
258                         'id'            => $comment['itemid'],
259                         'live'          => TRUE,
260                         'return'        => $continue
261                 );
262                 
263                 // begin if: member logged in
264                 if ( $member->isLoggedIn() )
265                 {
266                         $spamcheck['author'] = $member->displayname;
267                         $spamcheck['email'] = $member->email;
268                 }
269                 // else: public
270                 else
271                 {
272                         $spamcheck['author'] = $comment['user'];
273                         $spamcheck['email'] = $comment['email'];
274                         $spamcheck['url'] = $comment['userid'];
275                 }
276                 
277                 $manager->notify('SpamCheck', array('spamcheck' => &$spamcheck) );
278                 
279                 if ( !$continue && isset($spamcheck['result']) && $spamcheck['result'] == TRUE )
280                 {
281                         return _ERROR_COMMENTS_SPAM;
282                 }
283                 
284                 // isValidComment returns either "1" or an error message
285                 $isvalid = $this->isValidComment($comment, $spamcheck);
286                 if ( $isvalid != 1 )
287                 {
288                         return $isvalid;
289                 }
290                 
291                 // begin if: send email to notification address
292                 if ( $settings->getNotifyAddress() && $settings->notifyOnComment() )
293                 {
294                 
295                         $message = _NOTIFY_NC_MSG . ' ' . $this->itemid . "\n";
296                         $temp = parse_url($CONF['Self']);
297                         
298                         if ( $temp['scheme'] )
299                         {
300                                 $message .= Link::create_item_link($this->itemid) . "\n\n";
301                         }
302                         else
303                         {
304                                 $tempurl = $settings->getURL();
305                                 
306                                 if ( i18n::substr($tempurl, -1) == '/' || i18n::substr($tempurl, -4) == '.php' )
307                                 {
308                                         $message .= $tempurl . '?itemid=' . $this->itemid . "\n\n";
309                                 }
310                                 else
311                                 {
312                                         $message .= $tempurl . '/?itemid=' . $this->itemid . "\n\n";
313                                 }
314                         }
315                         
316                         if ( $comment['memberid'] == 0 )
317                         {
318                                 $message .= _NOTIFY_USER . ' ' . $comment['user'] . "\n";
319                                 $message .= _NOTIFY_USERID . ' ' . $comment['userid'] . "\n";
320                         }
321                         else
322                         {
323                                 $message .= _NOTIFY_MEMBER .' ' . $member->getDisplayName() . ' (ID=' . $member->getID() . ")\n";
324                         }
325                         
326                         $message .= _NOTIFY_HOST . ' ' . $comment['host'] . "\n";
327                         $message .= _NOTIFY_COMMENT . "\n " . $comment['body'] . "\n";
328                         $message .= NOTIFICATION::get_mail_footer();
329                         
330                         $item =& $manager->getItem($this->itemid, 0, 0);
331                         $subject = _NOTIFY_NC_TITLE . ' ' . strip_tags($item['title']) . ' (' . $this->itemid . ')';
332                         
333                         $from = $member->getNotifyFromMailAddress($comment['email']);
334                         
335                         NOTIFICATION::mail($settings->getNotifyAddress(), $subject, $message, $from, i18n::get_current_charset());
336                 }
337                 
338                 $comment = Comment::prepare($comment);
339                 
340                 $manager->notify('PreAddComment', array('comment' => &$comment, 'spamcheck' => &$spamcheck) );
341                 
342                 $name           = DB::quoteValue($comment['user']);
343                 $url            = DB::quoteValue($comment['userid']);
344                 $email          = DB::quoteValue($comment['email']);
345                 $body           = DB::quoteValue($comment['body']);
346                 $host           = DB::quoteValue($comment['host']);
347                 $ip                     = DB::quoteValue($comment['ip']);
348                 $memberid       = intval($comment['memberid']);
349                 $timestamp      = DB::formatDateTime($comment['timestamp']);
350                 $itemid         = $this->itemid;
351                 
352                 $qSql = 'SELECT COUNT(*) AS result '
353                       . 'FROM ' . sql_table('comment')
354                       . ' WHERE '
355                       .      'cmail   = ' . $url
356                       . ' AND cmember = ' . $memberid
357                       . ' AND cbody   = ' . $body
358                       . ' AND citem   = ' . $itemid
359                       . ' AND cblog   = ' . $blogid;
360                 $result = (integer) DB::getValue($qSql);
361                 
362                 if ( $result > 0 )
363                 {
364                         return _ERROR_BADACTION;
365                 }
366                 
367                 $query = sprintf('INSERT INTO %s (cuser, cmail, cemail, cmember, cbody, citem, ctime, chost, cip, cblog) '
368                         . 'VALUES (%s, %s, %s, %d, %s, %d, %s, %s, %s, %d)'
369                         , sql_table('comment'), $name, $url, $email, $memberid, $body, $itemid, $timestamp, $host, $ip, $blogid);
370                 
371                 DB::execute($query);
372                 
373                 // post add comment
374                 $commentid = DB::getInsertId();
375                 $manager->notify('PostAddComment', array('comment' => &$comment, 'commentid' => &$commentid, 'spamcheck' => &$spamcheck) );
376                 
377                 // succeeded !
378                 return TRUE;
379         }
380         
381         /**
382          * Comments::isValidComment()
383          * Checks if a comment is valid and call plugins
384          * that can check if the comment is a spam comment        
385          * 
386          * @param       array   $comment        array with comment elements
387          * @param       array   $spamcheck      array with spamcheck elements
388          * @return      boolean valid or not
389          */
390         private function isValidComment(&$comment, &$spamcheck)
391         {
392                 global $member, $manager;
393                 
394                 // check if there exists a item for this date
395                 $item =& $manager->getItem($this->itemid, 0, 0);
396                 
397                 if ( !$item )
398                 {
399                         return _ERROR_NOSUCHITEM;
400                 }
401                 
402                 if ( $item['closed'] )
403                 {
404                         return _ERROR_ITEMCLOSED;
405                 }
406                 
407                 // don't allow words that are too long
408                 if ( preg_match('/[a-zA-Z0-9|\.,;:!\?=\/\\\\]{90,90}/', $comment['body']) != 0 )
409                 {
410                         return _ERROR_COMMENT_LONGWORD;
411                 }
412                 
413                 // check lengths of comment
414                 if ( i18n::strlen($comment['body']) < 3 )
415                 {
416                         return _ERROR_COMMENT_NOCOMMENT;
417                 }
418                 
419                 if ( i18n::strlen($comment['body']) > 5000 )
420                 {
421                         return _ERROR_COMMENT_TOOLONG;
422                 }
423                 
424                 // only check username if no member logged in
425                 if ( !$member->isLoggedIn() && (i18n::strlen($comment['user']) < 2) )
426                 {
427                         return _ERROR_COMMENT_NOUSERNAME;
428                 }
429                 
430                 if ( (i18n::strlen($comment['email']) != 0) && !NOTIFICATION::address_validation(trim($comment['email'])) )
431                 {
432                         return _ERROR_BADMAILADDRESS;
433                 }
434                 
435                 // let plugins do verification (any plugin which thinks the comment is invalid
436                 // can change 'error' to something other than '1')
437                 $result = 1;
438                 $manager->notify('ValidateForm', array('type' => 'comment', 'comment' => &$comment, 'error' => &$result, 'spamcheck' => &$spamcheck) );
439                 
440                 return $result;
441         }
442 }