source: branches/1.3/libs/Comment.php @ 1738

Revision 1738, 20.0 KB checked in by nick_ramsay, 3 years ago (diff)

[Branch 1.3] Fixes for sending unprepared SQL queries to smartCache.

Line 
1<?php
2/**
3 * The Comment class contains some useful methods for using comments
4 *
5 * PHP version 5
6 *
7 * LICENSE: Hotaru CMS is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * Hotaru CMS is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with Hotaru CMS. If not, see http://www.gnu.org/licenses/.
18 *
19 * @category  Content Management System
20 * @package   HotaruCMS
21 * @author    Nick Ramsay <admin@hotarucms.org>
22 * @copyright Copyright (c) 2010, Hotaru CMS
23 * @license   http://www.gnu.org/copyleft/gpl.html GNU General Public License
24 * @link      http://www.hotarucms.org/
25 */
26   
27class Comment
28{
29        protected $id           = 0;
30        protected $parent       = 0;
31        protected $postId       = 0;
32        protected $author       = 0;
33        protected $date         = '';
34        protected $status       = 'approved';
35        protected $votes_up     = 0;
36        protected $votes_down   = 0;
37        protected $content      = '';
38        protected $type         = 'newcomment';   // or "editcomment"
39        protected $subscribe    = 0;
40        protected $levels       = 0;         // max nesting levels
41        protected $depth        = 0;         // this nesting level
42        protected $email        = '';
43        protected $allowableTags = '';
44        protected $itemsPerPage = 20;
45        protected $pagination   = '';
46        protected $thisForm     = '';
47        protected $allForms     = 'checked';
48        protected $avatars      = '';
49        protected $avatarSize   = 16;
50        protected $voting       = '';
51        protected $order        = 'asc';   // oldest comments first
52       
53       
54        /**
55         * Access modifier to set protected properties
56         */
57        public function __set($var, $val)
58        {
59                $this->$var = $val; 
60        }
61       
62       
63        /**
64         * Access modifier to get protected properties
65         */
66        public function __get($var)
67        {
68                return $this->$var;
69        }
70       
71       
72        /**
73         * Count comments
74         *
75         * @param bool $digits_only - return just the count (if false, returns "3 comments", etc.)
76         * @param string $no_comments_text - e.g. "Leave a comment" or "No comments"
77         * @return string - text to show, e.g. "3 comments"
78         */
79        function countComments($h, $digits_only = true, $no_comments_text = '')
80        {
81                $sql = "SELECT COUNT(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_post_id = %d AND comment_status = %s";
82                $query = $h->db->prepare($sql, $h->post->id, 'approved');
83               
84                $h->smartCache('on', 'comments', 60, $query); // start using cache
85                $num_comments = $h->db->get_var($query);
86                $h->smartCache('off'); // stop using cache
87               
88                if ($digits_only) { return $num_comments; } // just return the number
89               
90                if ($num_comments == 1) {
91                        return "1 " . $h->lang['comments_singular_link'];
92                } elseif ($num_comments > 1) {
93                        return $num_comments . " " . $h->lang['comments_plural_link'];
94                }
95               
96                return $no_comments_text;  // shows "Leave a comment" above comment form when no comments
97        }
98       
99       
100        /**
101         * Count all user comments
102         *
103         * @param int $user_id
104         * @return int
105         */
106        function countUserComments($h, $user_id = 0)
107        {
108                if (!$user_id) { $user_id = $h->currentUser->id; }
109               
110                $sql = "SELECT COUNT(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_user_id = %d AND comment_status = %s";
111                $query = $h->db->prepare($sql, $user_id , 'approved');
112               
113                $h->smartCache('on', 'comments', 60, $query); // start using cache
114                $num_comments = $h->db->get_var($query);
115                $h->smartCache('off'); // stop using cache
116               
117                return $num_comments;
118        }
119       
120       
121        /**
122         * Read all comment parents
123         *
124         * @param int $post_id - the id of the post this comment is on
125         * @param array|false
126         */
127        function readAllParents($h, $post_id, $order = "ASC")
128        {
129                $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_post_id = %d AND comment_parent = %d AND comment_status = %s ORDER BY comment_date " . $order;
130                $query = $h->db->prepare($sql, $post_id, 0, 'approved');
131               
132                $h->smartCache('on', 'comments', 60, $query); // start using cache
133                $parents = $h->db->get_results($query);
134                $h->smartCache('off'); // stop using cache
135               
136                if($parents) { return $parents; } else { return false; }
137        }
138       
139       
140        /**
141         * Read all comment children
142         *
143         * @param int $parent - the id of the parent comment
144         * @param array|false
145         */
146        function readAllChildren($h, $parent)
147        {
148                $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_parent = %d AND comment_status = %s ORDER BY comment_date";
149                $query = $h->db->prepare($sql, $parent, 'approved');
150               
151                $h->smartCache('on', 'comments', 60, $query); // start using cache
152                $children = $h->db->get_results($query);
153                $h->smartCache('off'); // stop using cache
154               
155                if($children) { return $children; } else { return false; }
156        }
157       
158       
159        /**
160         * Get comment from database
161         *
162         * @param int $comment_id
163         * @return array|false
164         */
165        function getComment($h, $comment_id = 0)
166        {
167                $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_id = %d";
168                $query = $h->db->prepare($sql, $comment_id);
169               
170                $h->smartCache('on', 'comments', 60, $query); // start using cache
171                $comment = $h->db->get_row($query);
172                $h->smartCache('off'); // stop using cache
173               
174                if($comment) { return $comment; } else { return false; }
175        }
176       
177       
178        /**
179         * Get all comments from database
180         *
181         * @param int $post_id - you can limit comments to a single post
182         * @return array|false
183         */
184        function getAllComments($h, $post_id = 0, $order = "ASC", $limit = 0, $userid = 0)
185        {
186                // limiting is used in the rssFeed function. Other than that, pagination does limiting for us.
187                if(!$limit) { $limit = ''; } else { $limit = " LIMIT "  .$limit; }
188               
189                if ($post_id) {
190                        // get all comments from specified post
191                        $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_post_id = %d AND comment_status = %s ORDER BY comment_date " . $order;
192                        $query = $h->db->prepare($sql, $post_id, 'approved');
193                        $h->smartCache('on', 'comments', 60, $query); // start using cache
194                        $comments = $h->db->get_results($query);
195                } else {
196                        // get all comments
197                        if ($userid) {
198                                $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s AND comment_status = %s AND comment_user_id = %d ORDER BY comment_date " . $order . $limit;
199                                $query = $h->db->prepare($sql, 'N', 'approved', $userid);
200                                $h->smartCache('on', 'comments', 60, $query); // start using cache
201                                $comments = $h->db->get_results($query);
202                        } else {
203                                $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s AND comment_status = %s ORDER BY comment_date " . $order . $limit;
204                                $query = $h->db->prepare($sql, 'N', 'approved');
205                                $h->smartCache('on', 'comments', 60, $query ); // start using cache
206                                $comments = $h->db->get_results($query );
207                        }
208                }
209                $h->smartCache('off'); // stop using cache
210               
211                if($comments) { return $comments; } else { return false; }
212        }
213       
214       
215        /**
216         * Get all comments from database
217         *
218         * @param int $post_id - you can limit comments to a single post
219         * @return array|false
220         */
221        function getAllCommentsCount($h, $order = "ASC", $userid = 0)
222        {
223                // get all comments
224                if ($userid) {
225                        $sql = "SELECT count(*) AS number FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s AND comment_status = %s AND comment_user_id = %d ORDER BY comment_date " . $order;
226                        $query = $h->db->prepare($sql, 'N', 'approved', $userid);
227                        $h->smartCache('on', 'comments', 60, $query); // start using cache
228                        $comment_count = $h->db->get_var($query);
229                } else {
230                        $sql = "SELECT count(*) AS number FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s AND comment_status = %s ORDER BY comment_date " . $order;
231                        $query = $h->db->prepare($sql, 'N', 'approved');
232                        $h->smartCache('on', 'comments', 60, $query); // start using cache
233                        $comment_count = $h->db->get_var($query);
234                }
235                $h->smartCache('off'); // stop using cache
236               
237                if($comment_count) { return $comment_count; } else { return false; }
238        }
239       
240       
241        /**
242         * Get all comments from database
243         *
244         * @param int $post_id - you can limit comments to a single post
245         * @return array|false
246         */
247        function getAllCommentsQuery($h, $order = "ASC", $userid = 0)
248        {
249                // get all comments
250                if ($userid) {
251                        $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_status = %s AND comment_user_id = %d ORDER BY comment_date " . $order;
252                        $query = $h->db->prepare($sql, 'approved', $userid);
253                } else {
254                        $sql = "SELECT * FROM " . TABLE_COMMENTS . " WHERE comment_status = %s ORDER BY comment_date " . $order;
255                        $query = $h->db->prepare($sql, 'approved');
256                }
257               
258                if($query) { return $query; } else { return false; }
259        }
260       
261       
262        /**
263         * Read comment
264         *
265         * @param array $comment
266         */
267        function readComment($h, $comment = array())
268        {
269                $this->id = $comment->comment_id;
270                $this->parent = $comment->comment_parent;
271                $this->postId = $comment->comment_post_id;
272                $this->author = $comment->comment_user_id;
273                $this->date = $comment->comment_date;
274                $this->status = $comment->comment_status;
275                $this->votes_up = $comment->comment_votes_up;
276                $this->votes_down = $comment->comment_votes_down;
277                $this->content = urldecode($comment->comment_content);
278                $this->subscribe = $comment->comment_subscribe;
279               
280                $h->pluginHook('comment_read_comment');
281               
282                return $this;
283        }
284       
285       
286        /**
287         * Add comment
288         *
289         * @return true
290         */
291        function addComment($h)
292        {
293                $result = array(); // this will be sent back containing various info
294               
295                // setup
296                $result['set_pending'] = '';
297                $result['comments_approved'] = 0;
298                $result['comments_needed'] = 0;
299                $result['exceeded_daily_limit'] = false;
300                $result['exceeded_url_limit'] = false;
301                $result['under_moderation'] = false;
302                $result['not_enough_comments'] = false;
303               
304                $h->pluginHook('comment_pre_add_comment');  // Akismet uses this to change the status
305               
306                $can_comment = $h->currentUser->getPermission('can_comment'); // This was already checked, but Akismet sometimes reverts the status, so we do it again.
307               
308                if ($can_comment == 'mod') { // forces all to 'pending' if user's comments are moderated
309                        $this->status = 'pending';
310                        $result['under_moderation'] = true;
311                }
312               
313                // Get settings from database...
314                $comments_settings = $h->getSerializedSettings('comments');
315               
316                $set_pending = $comments_settings['comment_set_pending'];
317                $daily_limit = $comments_settings['comment_daily_limit'];
318                $url_limit = $comments_settings['comment_url_limit'];
319               
320                $result['set_pending'] = $set_pending;
321               
322                if ($h->currentUser->role == 'member')
323                {
324                        if ($daily_limit && ($daily_limit < $this->countDailyComments($h)))
325                        {
326                                 // exceeded daily limit, set to pending
327                                $this->status = 'pending';
328                                $result['exceeded_daily_limit'] = true;
329                        }
330                       
331                        if ($url_limit && ($url_limit < $this->countUrls()))
332                        {
333                                // exceeded url limit, set to pending
334                                $this->status = 'pending';
335                                $result['exceeded_url_limit'] = true;
336                        }
337                       
338                }
339
340                if ($set_pending == 'some_pending') {
341                        $comments_approved = $this->commentsApproved($h, $h->currentUser->id);
342                        $x_comments_needed = $comments_settings['comment_x_comments'];
343                        if ($comments_approved < $x_comments_needed) {
344                                $result['not_enough_comments'] = true;
345                                $this->status = 'pending';
346                        }
347                }
348               
349                if ($set_pending == 'all_pending') {
350                        $this->status = 'pending';
351                }
352               
353                $sql = "INSERT INTO " . TABLE_COMMENTS . " SET comment_post_id = %d, comment_user_id = %d, comment_parent = %d, comment_date = CURRENT_TIMESTAMP, comment_status = %s, comment_content = %s, comment_subscribe = %d, comment_updateby = %d";
354               
355                $h->db->query($h->db->prepare($sql, $this->postId, $this->author, $this->parent, $this->status, urlencode(trim(stripslashes($this->content))), $this->subscribe, $h->currentUser->id));
356               
357                $last_insert_id = $h->db->get_var($h->db->prepare("SELECT LAST_INSERT_ID()"));
358               
359                $this->id = $last_insert_id;
360                $h->vars['last_insert_id'] = $last_insert_id;    // make it available outside this class
361               
362                $h->pluginHook('comment_post_add_comment');
363               
364                return $result;
365        }
366
367               
368        /**
369         * Edit comment
370         *
371         * @return true
372         */
373        function editComment($h)
374        {
375                $sql = "UPDATE " . TABLE_COMMENTS . " SET comment_status = %s, comment_content = %s, comment_subscribe = %d, comment_updateby = %d WHERE comment_id = %d";
376                $h->db->query($h->db->prepare($sql, $this->status, urlencode(trim(stripslashes($this->content))), $this->subscribe, $h->currentUser->id, $this->id));
377               
378                $h->comment->id = $this->id; // a small hack to get the id for use in plugins.
379                $h->pluginHook('comment_update_comment');
380               
381                return true;
382        }
383       
384       
385        /**
386         * Physically delete a comment from the database
387         *
388         */   
389        public function deleteComment($h, $comment_id = 0)
390        {
391                if (!$comment_id) { $comment_id = $this->id; }
392                if (!$comment_id) { return false; }
393               
394                $sql = "DELETE FROM " . TABLE_COMMENTS . " WHERE comment_id = %d";
395                $h->db->query($h->db->prepare($sql, $comment_id));
396               
397                // delete any votes for this comment
398                $sql = "DELETE FROM " . TABLE_COMMENTVOTES . " WHERE cvote_comment_id = %d";
399                $h->db->query($h->db->prepare($sql, $this->id));
400               
401                $h->comment->id = $comment_id; // a small hack to get the id for use in plugins.
402                $h->pluginHook('comment_delete_comment');
403               
404                // Need to clear both these caches to be sure related items are updated in widgets, etc.:
405                $h->clearCache('html_cache', false);
406                $h->clearCache('db_cache', false);
407        }
408       
409       
410        /**
411         * Physically delete all comments by a specified user (and responses)
412         *
413         * @param array $user_id
414         * @return bool
415         */
416        public function deleteComments($h, $user_id = 0)
417        {
418                if (!$user_id) { return false; }
419               
420                $sql = "SELECT comment_id FROM " . DB_PREFIX . "comments WHERE comment_user_id = %d";
421                $results = $h->db->get_results($h->db->prepare($sql, $user_id));
422               
423                if ($results) {
424                        foreach ($results as $r) {
425                                $h->comment->id = $r->comment_id;   // used by other plugins in "comment_delete_comment" function/hook
426                                $this->deleteComment($h, $h->comment->id);    // delete parent comment
427                                $this->deleteCommentTree($h, $h->comment->id);  // delete all children of that comment regardless of user
428                        }
429                }
430               
431                return true;
432        }
433       
434       
435        /**
436         * Recurse through comment tree, deleting all
437         *
438         * @param int $comment_id - id of current comment
439         * @return bool
440         */
441        public function deleteCommentTree($h, $comment_id)
442        {
443                while ($children = $this->readAllChildren($h, $comment_id)) {
444                        foreach ($children as $child) {
445                                $this->readComment($h, $child);
446                                $this->deleteComment($h, $this->id);
447                                if ($this->deletecommentTree($h, $this->id)) {
448                                        return true;
449                                }
450                        }
451       
452                        return false;
453                }
454        }
455       
456       
457        /**
458         * Recurse through comment tree, setting all to 'pending'
459         *
460         * @param int $comment_id - id of current comment
461         * @return bool
462         */
463        public function setPendingCommentTree($h, $comment_id)
464        {
465                while ($children = $this->readAllChildren($h, $comment_id)) {
466                        foreach ($children as $child) {
467                                $this->readComment($h, $child);
468                                $this->status = 'pending';
469                                $this->editComment($h);
470                                if ($this->setPendingCommentTree($h, $this->id)) {
471                                        return true;
472                                }
473                        }
474                       
475                        return false;
476                }
477        }
478       
479       
480        /**
481         * Determine if the comment form is open or closed
482         *
483         * @param int $post_id
484         * @return string 'open' or 'closed'
485         */
486        function formStatus($h, $type)
487        {
488                if ($type == 'select') {
489                        $sql = "SELECT post_comments FROM " . TABLE_POSTS . " WHERE post_id = %d";
490                        $form_status = $h->db->get_var($h->db->prepare($sql, $h->post->id));
491                       
492                        if ($form_status) { return $form_status; } else { return 'open'; } // default 'open'
493                }
494               
495                if ($type == 'open' || $type == 'closed') {
496                        $h->comment->form = $type;
497                        $sql = "UPDATE " . TABLE_POSTS . " SET post_comments = %s WHERE post_id = %d";
498                        $h->db->query($h->db->prepare($sql, $type, $h->post->id));
499                }
500        }
501       
502       
503        /**
504         * Unsubscribe from a thread
505         *
506         * @param int $post_id
507         * @return true
508         */
509        function unsubscribe($h, $post_id)
510        {
511                $h->readPost($post_id);
512       
513                $sql = "UPDATE " . TABLE_COMMENTS . " SET comment_subscribe = %d WHERE comment_post_id = %d AND comment_user_id = %d";
514                $h->db->query($h->db->prepare($sql, 0, $h->post->id, $h->currentUser->id));
515
516                // Check if the currentUser is the post author
517                if ($h->post->author == $h->currentUser->id) {
518                // Check if the user subscribed to comments as a submitter
519                        if ($h->post->subscribe == 1) {
520                                $sql = "UPDATE " . TABLE_POSTS . " SET post_subscribe = %d WHERE post_id = %d AND post_author = %d";
521                                $h->db->query($h->db->prepare($sql, 0, $h->post->id, $h->currentUser->id));
522                        }
523                }
524                return true;
525        }
526       
527       
528        /**
529         * Update thread subscription
530         *
531         * @param int $post_id
532         * @return true
533         */
534        function updateSubscribe($h, $post_id)
535        {
536                if ($this->subscribe == 1)
537                {
538                        $sql = "UPDATE " . TABLE_COMMENTS . " SET comment_subscribe = %d WHERE comment_post_id = %d AND comment_user_id = %d";
539                        $h->db->query($h->db->prepare($sql, 1, $h->post->id, $h->currentUser->id));
540                }
541                else
542                {
543                        $this->unsubscribe($h, $post_id);
544                }
545        }
546       
547       
548        /**
549         * Count how many approved comments a user has had
550         *
551         * @param int $userid
552         * @return int
553         */
554        public function commentsApproved($h, $userid)
555        {
556                $sql = "SELECT COUNT(*) FROM " . TABLE_COMMENTS . " WHERE comment_status = %s AND comment_user_id = %d";
557                $query = $h->db->prepare($sql, 'approved', $userid);
558               
559                $h->smartCache('on', 'comments', 60, $query); // start using cache
560                $count = $h->db->get_var($query);
561                $h->smartCache('off'); // stop using cache
562               
563                return $count;
564        }
565       
566       
567        /**
568         * Count daily comments for this commenter
569         *
570         * @return int
571         */
572        public function countDailyComments($h)
573        {
574                $start = date('YmdHis', time_block());
575                $end = date('YmdHis', strtotime("-1 day"));
576                $sql = "SELECT COUNT(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s AND comment_user_id = %d AND (comment_date >= %s AND comment_date <= %s)";
577                $query = $h->db->prepare($sql, 'N', $this->author, $end, $start);
578               
579                $h->smartCache('on', 'comments', 60, $query); // start using cache
580                $count = $h->db->get_var($query);
581                $h->smartCache('off'); // stop using cache
582               
583                return $count;
584        }
585       
586       
587        /**
588         * Count urls in comment
589         *
590         * @return int
591         * @link http://www.liamdelahunty.com/tips/php_url_count_check_for_comment_spam.php
592         */
593        public function countUrls()
594        {
595                $text = $this->content;
596               
597                //$http = substr_count($text, "http");
598                $href = substr_count($text, "href");
599                $url = substr_count($text, "[url");
600               
601                return $href + $url;
602        }
603       
604       
605        /**
606         * Stats for Admin homepage
607         *
608         * @param string $stat_type
609         * @return int
610         */
611        public function stats($h, $stat_type = '')
612        {
613                switch ($stat_type) {
614                        case 'total_comments':
615                                $query = "SELECT count(comment_id) FROM " . TABLE_COMMENTS;
616                                $h->smartCache('on', 'comments', 60, $query); // start using cache
617                                $comments = $h->db->get_var($query);
618                                break;
619                        case 'approved_comments':
620                                $sql = "SELECT count(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_status = %s";
621                                $query = $h->db->prepare($sql, 'approved');
622                                $h->smartCache('on', 'comments', 60, $query); // start using cache
623                                $comments = $h->db->get_var($query);
624                                break;
625                        case 'pending_comments':
626                                $sql = "SELECT count(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_status = %s";
627                                $query = $h->db->prepare($sql, 'pending');
628                                $h->smartCache('on', 'comments', 60, $query); // start using cache
629                                $comments = $h->db->get_var($query);
630                                break;
631                        case 'archived_comments':
632                                $sql = "SELECT count(comment_id) FROM " . TABLE_COMMENTS . " WHERE comment_archived = %s";
633                                $query = $h->db->prepare($sql, 'Y');
634                                $h->smartCache('on', 'comments', 60, $query); // start using cache
635                                $comments = $h->db->get_var($query);
636                                break;
637                        default:
638                                $comments = '';
639                }
640                $h->smartCache('off'); // stop using cache
641               
642                return $comments;
643        }
644}
645?>
Note: See TracBrowser for help on using the repository browser.