OSDN Git Service

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